[no ci] Hisilicon: add hisilicon-osdrv-serdes package (#1154)

Co-authored-by: Signor Pellegrino <68112357+FlyRouter@users.noreply.github.com>
pull/1158/head
viktorxda 2023-11-22 18:22:40 +01:00 committed by GitHub
parent f003efd390
commit 511b2d4c8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 2712 additions and 9 deletions

View File

@ -25,7 +25,6 @@ source "$BR2_EXTERNAL_GENERAL_PATH/package/goke-osdrv-gk7205v200/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/grainmedia-osdrv-gm8136/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/grainmedia-osdrv-gm8136/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisi-gpio/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisi-gpio/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-opensdk/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-opensdk/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv1-sources/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516av100/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516av100/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516cv100/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516cv100/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516cv200/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516cv200/Config.in"
@ -34,15 +33,19 @@ source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516cv500/Config.in
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516ev200/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516ev200/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3519v101/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3519v101/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3536dv100/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3536dv100/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-serdes/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv1-sources/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/i2c-telemetry/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/i2c-telemetry/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-motors-t31/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-atbm603x-sdio-t31/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-atbm603x-sdio-t31/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-libimp-control/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-motors-t31/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-opensdk/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-opensdk/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t20/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t20/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t21/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t21/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t30/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t30/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t31/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t31/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t40/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t40/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-pwm/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ipctool/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ipctool/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/json-c-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/json-c-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/jsonfilter/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/jsonfilter/Config.in"
@ -51,22 +54,23 @@ source "$BR2_EXTERNAL_GENERAL_PATH/package/libcurl-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/libevent-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/libevent-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/libhv-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/libhv-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/libogg-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/libogg-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/librem-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/libre-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/libre-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/librem-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/libsrt-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/libsrt-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/libsrtp-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/libsrtp-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/libwebsockets-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/libwebsockets-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/linux-firmware-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/linux-firmware-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/linux-patcher/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/linux-patcher/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/majestic/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/logcat-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/majestic-fonts/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/majestic-fonts/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/majestic/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/mavfwd/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/mavfwd/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/mavlink-router/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/mavlink-router/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/mbedtls-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/mbedtls-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/microbe-web/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/microbe-web/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/microsnander/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/microsnander/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/mini/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/mini-snmpd-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/mini-snmpd-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/mini/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/motors/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/motors/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/mt7601u-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/mt7601u-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/nabto/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/nabto/Config.in"
@ -80,8 +84,8 @@ source "$BR2_EXTERNAL_GENERAL_PATH/package/rockchip-osdrv-rv11xx/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8188eus-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8188eus-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8188fu-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8188fu-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8188fu-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8188fu-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8189fs-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8189es-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8189es-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8189fs-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8192eu-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8192eu-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8733bu-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8733bu-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8812au-openipc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/rtl8812au-openipc/Config.in"
@ -106,6 +110,3 @@ source "$BR2_EXTERNAL_GENERAL_PATH/package/xiongmai-osdrv-xm530/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/xmdp/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/xmdp/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/yaml-cli/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/yaml-cli/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/zerotier-one/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/zerotier-one/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/logcat-openipc/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-pwm/Config.in"
source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-libimp-control/Config.in"

View File

@ -0,0 +1,4 @@
config BR2_PACKAGE_HISILICON_OSDRV_SERDES
bool "hisilicon-osdrv-serdes"
help
HiSilicon SerDes kernel driver.

View File

@ -0,0 +1,14 @@
################################################################################
#
# hisilicon-osdrv-serdes
#
################################################################################
HISILICON_OSDRV_SERDES_SITE_METHOD = local
HISILICON_OSDRV_SERDES_SITE = $(HISILICON_OSDRV_SERDES_PKGDIR)/src
HISILICON_OSDRV_SERDES_MODULE_MAKE_OPTS = \
KSRC=$(LINUX_DIR)
$(eval $(kernel-module))
$(eval $(generic-package))

View File

@ -0,0 +1,9 @@
obj-m := hi_serdes.o
hi_serdes-objs := serdes_comm.o thine_241a242_serdes.o
ccflags-y := -I $(PWD)/include
modules:
$(MAKE) -C $(KSRC) M=$(PWD) modules
clean:
$(MAKE) -C $(KSRC) M=$(PWD) clean

View File

@ -0,0 +1,571 @@
#ifndef __HI_OSAL__
#define __HI_OSAL__
#define HI_OSAL_VERSION "1.0"
#include "osal_list.h"
#define osal_gfp_kernel 0
#define osal_gfp_atomic 1
extern void *osal_vmalloc(unsigned long size);
extern void osal_vfree(const void *addr);
extern void *osal_kmalloc(unsigned long size, unsigned int osal_gfp_flag);
extern void osal_kfree(const void *addr);
// atomic api
typedef struct {
void *atomic;
} osal_atomic_t;
#define OSAL_ATOMIC_INIT(i) { (i) }
extern int osal_atomic_init(osal_atomic_t *atomic);
extern void osal_atomic_destory(osal_atomic_t *atomic);
extern int osal_atomic_read(osal_atomic_t *v);
extern void osal_atomic_set(osal_atomic_t *v, int i);
extern int osal_atomic_inc_return(osal_atomic_t *v);
extern int osal_atomic_dec_return(osal_atomic_t *v);
// semaphore api
#define EINTR 4
typedef struct osal_semaphore {
void *sem;
} osal_semaphore_t;
extern int osal_sema_init(osal_semaphore_t *sem, int val);
extern int osal_down(osal_semaphore_t *sem);
extern int osal_down_interruptible(osal_semaphore_t *sem);
extern int osal_down_trylock(osal_semaphore_t *sem);
extern void osal_up(osal_semaphore_t *sem);
// notice:must be called when kmod exit, other wise will lead to memory leak;
extern void osal_sema_destory(osal_semaphore_t *sem);
// mutex api
typedef struct osal_mutex {
void *mutex;
} osal_mutex_t;
extern int osal_mutex_init(osal_mutex_t *mutex);
extern int osal_mutex_lock(osal_mutex_t *mutex);
extern int osal_mutex_lock_interruptible(osal_mutex_t *mutex);
extern int osal_mutex_trylock(osal_mutex_t *mutex);
extern void osal_mutex_unlock(osal_mutex_t *mutex);
// notice:must be called when kmod exit, other wise will lead to memory leak;
extern void osal_mutex_destory(osal_mutex_t *mutex);
// spin lock api
typedef struct osal_spinlock {
void *lock;
} osal_spinlock_t;
extern int osal_spin_lock_init(osal_spinlock_t *lock);
extern void osal_spin_lock(osal_spinlock_t *lock);
extern int osal_spin_trylock(osal_spinlock_t *lock);
extern void osal_spin_unlock(osal_spinlock_t *lock);
extern void osal_spin_lock_irqsave(osal_spinlock_t *lock, unsigned long *flags);
extern void osal_spin_unlock_irqrestore(osal_spinlock_t *lock, unsigned long *flags);
// notice:must be called when kmod exit, other wise will lead to memory leak;
extern void osal_spin_lock_destory(osal_spinlock_t *lock);
// wait api
typedef int (*osal_wait_cond_func_t)(const void *param);
typedef struct osal_wait {
void *wait;
} osal_wait_t;
#define ERESTARTSYS 512
extern unsigned long osal_msecs_to_jiffies(const unsigned int m);
extern int osal_wait_init(osal_wait_t *wait);
extern int osal_wait_interruptible(osal_wait_t *wait, osal_wait_cond_func_t func, void *param);
extern int osal_wait_uninterruptible(osal_wait_t *wait, osal_wait_cond_func_t func, void *param);
extern int osal_wait_timeout_interruptible(osal_wait_t *wait, osal_wait_cond_func_t func, void *param,
unsigned long ms);
extern int osal_wait_timeout_uninterruptible(osal_wait_t *wait, osal_wait_cond_func_t func, void *param,
unsigned long ms);
#define osal_wait_event_interruptible(wait, func, param) \
({ \
int __ret = 0; \
\
for (;;) { \
if (func(param)) { \
__ret = 0; \
break; \
} \
__ret = osal_wait_timeout_interruptible(wait, (func), param, 100); \
if (__ret < 0) \
break; \
} \
__ret; \
})
#define osal_wait_event_uninterruptible(wait, func, param) \
({ \
int __ret = 0; \
\
for (;;) { \
if (func(param)) { \
__ret = 0; \
break; \
} \
__ret = osal_wait_uninterruptible(wait, (func), param); \
if (__ret < 0) \
break; \
} \
__ret; \
})
#define osal_wait_event_timeout_interruptible(wait, func, param, timeout) \
({ \
int __ret = timeout; \
\
if ((func(param)) && !timeout) { \
__ret = 1; \
} \
\
for (;;) { \
if (func(param)) { \
__ret = osal_msecs_to_jiffies(__ret); \
break; \
} \
__ret = osal_wait_timeout_interruptible(wait, (func), param, __ret); \
if (!__ret || __ret == -ERESTARTSYS) \
break; \
} \
__ret; \
})
#define osal_wait_event_timeout_uninterruptible(wait, func, param, timeout) \
({ \
int __ret = timeout; \
\
if ((func(param)) && !timeout) { \
__ret = 1; \
} \
\
for (;;) { \
if (func(param)) { \
__ret = osal_msecs_to_jiffies(__ret); \
break; \
} \
__ret = osal_wait_timeout_uninterruptible(wait, (func), param, __ret); \
if (!__ret || __ret == -ERESTARTSYS) \
break; \
} \
__ret; \
})
extern void osal_wakeup(osal_wait_t *wait); // same as wake_up_all
extern void osal_wait_destory(osal_wait_t *wait);
// workqueue api
typedef struct osal_work_struct {
void *work;
void (*func)(struct osal_work_struct *work);
} osal_work_struct_t;
typedef void (*osal_work_func_t)(struct osal_work_struct *work);
extern int osal_init_work(struct osal_work_struct *work, osal_work_func_t func);
#define OSAL_INIT_WORK(_work, _func) \
do { \
osal_init_work((_work), (_func)); \
} while (0)
extern int osal_schedule_work(struct osal_work_struct *work);
extern void osal_destroy_work(struct osal_work_struct *work);
// shedule
extern void osal_yield(void);
// interrupt api
enum osal_irqreturn {
OSAL_IRQ_NONE = (0 << 0),
OSAL_IRQ_HANDLED = (1 << 0),
OSAL_IRQ_WAKE_THREAD = (1 << 1),
};
typedef int (*osal_irq_handler_t)(int, void *);
extern int osal_request_irq(unsigned int irq, osal_irq_handler_t handler, osal_irq_handler_t thread_fn,
const char *name, void *dev);
extern void osal_free_irq(unsigned int irq, void *dev);
extern int osal_in_interrupt(void);
#define OSAL_DIS_IRQ_CNT 2
typedef void (*osal_gic_handle_t)(unsigned int, unsigned int, void *);
extern int osal_register_gic_handle(unsigned int index, unsigned int irq, osal_gic_handle_t handle, const char *name,
void *dev);
extern int osal_unregister_gic_handle(unsigned int index, unsigned int irq, void *dev);
// task api
typedef struct osal_task {
void *task_struct;
} osal_task_t;
typedef int (*threadfn_t)(void *data);
extern osal_task_t *osal_kthread_create(threadfn_t thread, void *data, const char *name);
extern void osal_kthread_destory(osal_task_t *task, unsigned int stop_flag);
// string api
extern char *osal_strcpy(char *s1, const char *s2);
extern char *osal_strncpy(char *s1, const char *s2, int size);
extern int osal_strlcpy(char *s1, const char *s2, int size);
extern char *osal_strcat(char *s1, const char *s2);
extern char *osal_strncat(char *s1, const char *s2, int size);
extern int osal_strlcat(char *s1, const char *s2, int size);
extern int osal_strcmp(const char *s1, const char *s2);
extern int osal_strncmp(const char *s1, const char *s2, int size);
extern int osal_strnicmp(const char *s1, const char *s2, int size);
extern int osal_strcasecmp(const char *s1, const char *s2);
extern int osal_strncasecmp(const char *s1, const char *s2, int n);
extern char *osal_strchr(const char *s, int n);
extern char *osal_strnchr(const char *s, int count, int c);
extern char *osal_strrchr(const char *s, int c);
extern char *osal_strstr(const char *s1, const char *s2);
extern char *osal_strnstr(const char *s1, const char *s2, int n);
extern int osal_strlen(const char *s);
extern int osal_strnlen(const char *s, int size);
extern char *osal_strpbrk(const char *s1, const char *s2);
extern char *osal_strsep(char **s, const char *ct);
extern int osal_strspn(const char *s, const char *accept);
extern int osal_strcspn(const char *s, const char *reject);
extern void *osal_memset(void *str, int c, int count);
extern void *osal_memcpy(void *s1, const void *s2, int count);
extern void *osal_memmove(void *s1, const void *s2, int count);
extern void *osal_memscan(void *addr, int c, int size);
extern int osal_memcmp(const void *cs, const void *ct, int count);
extern void *osal_memchr(const void *s, int c, int n);
extern void *osal_memchr_inv(const void *s, int c, int n);
extern unsigned long long osal_strtoull(const char *cp, char **endp, unsigned int base);
extern unsigned long osal_strtoul(const char *cp, char **endp, unsigned int base);
extern long osal_strtol(const char *cp, char **endp, unsigned int base);
extern long long osal_strtoll(const char *cp, char **endp, unsigned int base);
extern int osal_snprintf(char *buf, int size, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
extern int osal_scnprintf(char *buf, int size, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
extern int osal_sprintf(char *buf, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
extern int osal_sscanf(const char *buf, const char *fmt, ...);
// addr translate
extern void *osal_ioremap(unsigned long phys_addr, unsigned long size);
extern void *osal_ioremap_nocache(unsigned long phys_addr, unsigned long size);
extern void *osal_ioremap_cached(unsigned long phys_addr, unsigned long size);
extern void osal_iounmap(void *addr);
#define osal_readl(x) (*((volatile int *)(x)))
#define osal_writel(v, x) (*((volatile int *)(x)) = (v))
extern unsigned long osal_copy_from_user(void *to, const void *from, unsigned long n);
extern unsigned long osal_copy_to_user(void *to, const void *from, unsigned long n);
#define OSAL_VERIFY_READ 0
#define OSAL_VERIFY_WRITE 1
extern int osal_access_ok(int type, const void *addr, unsigned long size);
// cache api
extern void osal_flush_cache_all(void);
extern void osal_cpuc_flush_dcache_area(void *addr, int size);
extern void osal_flush_dcache_area(void *kvirt, unsigned long phys_addr, unsigned long length);
extern int osal_flush_dcache_all(void);
// math
extern unsigned long long osal_div_u64(unsigned long long dividend, unsigned int divisor);
extern long long osal_div_s64(long long dividend, int divisor);
extern unsigned long long osal_div64_u64(unsigned long long dividend, unsigned long long divisor);
extern long long osal_div64_s64(long long dividend, long long divisor);
extern unsigned long long osal_div_u64_rem(unsigned long long dividend, unsigned int divisor);
extern long long osal_div_s64_rem(long long dividend, int divisor);
extern unsigned long long osal_div64_u64_rem(unsigned long long dividend, unsigned long long divisor);
extern unsigned int osal_random(void);
#define osal_max(x, y) ({ \
__typeof__(x) _max1 = (x); \
__typeof__(y) _max2 = (y); \
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
#define osal_min(x, y) ({ \
__typeof__(x) _min1 = (x); \
__typeof__(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
#define osal_abs(x) ({ \
long ret; \
if (sizeof(x) == sizeof(long)) { \
long __x = (x); \
ret = (__x < 0) ? -__x : __x; \
} else { \
int __x = (x); \
ret = (__x < 0) ? -__x : __x; \
} \
ret; \
})
// barrier
extern void osal_mb(void);
extern void osal_rmb(void);
extern void osal_wmb(void);
extern void osal_smp_mb(void);
extern void osal_smp_rmb(void);
extern void osal_smp_wmb(void);
extern void osal_isb(void);
extern void osal_dsb(void);
extern void osal_dmb(void);
// debug
extern int osal_printk(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
extern void osal_panic(const char *fmt, const char *fun, int line, const char *);
#define OSAL_BUG() \
do { \
} while (1)
#define OSAL_ASSERT(expr) \
do { \
if (!(expr)) { \
osal_printk("\nASSERT failed at:\n" \
" >Condition: %s\n", \
#expr); \
OSAL_BUG(); \
} \
} while (0)
#define OSAL_BUG_ON(expr) \
do { \
if (expr) { \
osal_printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
OSAL_BUG(); \
} \
} while (0)
// proc
typedef struct osal_proc_dir_entry {
char name[50];
void *proc_dir_entry;
int (*open)(struct osal_proc_dir_entry *entry);
int (*read)(struct osal_proc_dir_entry *entry);
int (*write)(struct osal_proc_dir_entry *entry, const char *buf, int count, long long *);
void *private;
void *seqfile;
struct osal_list_head node;
} osal_proc_entry_t;
extern osal_proc_entry_t *osal_create_proc_entry(const char *name, osal_proc_entry_t *parent);
extern osal_proc_entry_t *osal_proc_mkdir(const char *name, osal_proc_entry_t *parent);
extern void osal_remove_proc_entry(const char *name, osal_proc_entry_t *parent);
extern int osal_seq_printf(osal_proc_entry_t *entry, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
// device api
#ifndef _IOC_TYPECHECK
#include "osal_ioctl.h"
#endif
typedef struct osal_dev {
char name[48];
void *dev;
int minor;
struct osal_fileops *fops;
struct osal_pmops *osal_pmops;
} osal_dev_t;
typedef struct osal_vm {
void *vm;
} osal_vm_t;
#define OSAL_POLLIN 0x0001
#define OSAL_POLLPRI 0x0002
#define OSAL_POLLOUT 0x0004
#define OSAL_POLLERR 0x0008
#define OSAL_POLLHUP 0x0010
#define OSAL_POLLNVAL 0x0020
#define OSAL_POLLRDNORM 0x0040
#define OSAL_POLLRDBAND 0x0080
#define OSAL_POLLWRNORM 0x0100
typedef struct osal_poll {
void *poll_table;
void *data;
} osal_poll_t;
typedef struct osal_fileops {
int (*open)(void *private_data);
int (*read)(char *buf, int size, long *offset, void *private_data);
int (*write)(const char *buf, int size, long *offset, void *private_data);
long (*llseek)(long offset, int whence, void *private_data);
int (*release)(void *private_data);
long (*unlocked_ioctl)(unsigned int cmd, unsigned long arg, void *private_data);
unsigned int (*poll)(osal_poll_t *osal_poll, void *private_data);
int (*mmap)(osal_vm_t *vm, unsigned long start, unsigned long end, unsigned long vm_pgoff, void *private_data);
#ifdef CONFIG_COMPAT
long (*compat_ioctl)(unsigned int cmd, unsigned long arg, void *private_data);
#endif
} osal_fileops_t;
typedef struct osal_pmops {
int (*pm_prepare)(osal_dev_t *dev);
void (*pm_complete)(osal_dev_t *dev);
int (*pm_suspend)(osal_dev_t *dev);
int (*pm_resume)(osal_dev_t *dev);
int (*pm_freeze)(osal_dev_t *dev);
int (*pm_thaw)(osal_dev_t *dev);
int (*pm_poweroff)(osal_dev_t *dev);
int (*pm_restore)(osal_dev_t *dev);
int (*pm_suspend_late)(osal_dev_t *dev);
int (*pm_resume_early)(osal_dev_t *dev);
int (*pm_freeze_late)(osal_dev_t *dev);
int (*pm_thaw_early)(osal_dev_t *dev);
int (*pm_poweroff_late)(osal_dev_t *dev);
int (*pm_restore_early)(osal_dev_t *dev);
int (*pm_suspend_noirq)(osal_dev_t *dev);
int (*pm_resume_noirq)(osal_dev_t *dev);
int (*pm_freeze_noirq)(osal_dev_t *dev);
int (*pm_thaw_noirq)(osal_dev_t *dev);
int (*pm_poweroff_noirq)(osal_dev_t *dev);
int (*pm_restore_noirq)(osal_dev_t *dev);
} osal_pmops_t;
#define OSAL_SEEK_SET 0
#define OSAL_SEEK_CUR 1
#define OSAL_SEEK_END 2
// #define PAGE_SHIFT 12
extern osal_dev_t *osal_createdev(const char *name);
extern int osal_destroydev(osal_dev_t *pdev);
extern int osal_registerdevice(osal_dev_t *pdev);
extern void osal_deregisterdevice(osal_dev_t *pdev);
extern void osal_poll_wait(osal_poll_t *table, osal_wait_t *wait);
extern void osal_pgprot_noncached(osal_vm_t *vm);
extern void osal_pgprot_cached(osal_vm_t *vm);
extern void osal_pgprot_writecombine(osal_vm_t *vm);
extern void osal_pgprot_stronglyordered(osal_vm_t *vm);
extern int osal_remap_pfn_range(osal_vm_t *vm, unsigned long addr, unsigned long pfn, unsigned long size);
extern int osal_io_remap_pfn_range(osal_vm_t *vm, unsigned long addr, unsigned long pfn, unsigned long size);
// timer
typedef struct osal_timer {
void *timer;
void (*function)(unsigned long);
unsigned long data;
} osal_timer_t;
typedef struct osal_timeval {
long tv_sec;
long tv_usec;
} osal_timeval_t;
typedef struct osal_rtc_time {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
} osal_rtc_time_t;
/* Return values for the timer callback function */
typedef enum hiOSAL_HRTIMER_RESTART_E {
OSAL_HRTIMER_NORESTART, /* < The timer will not be restarted. */
OSAL_HRTIMER_RESTART /* < The timer must be restarted. */
} OSAL_HRTIMER_RESTART_E;
/* hrtimer struct */
typedef struct osal_hrtimer {
void *timer;
OSAL_HRTIMER_RESTART_E (*function)(void *timer);
unsigned long interval; /* Unit ms */
} osal_hrtimer_t;
extern int osal_hrtimer_create(osal_hrtimer_t *phrtimer);
extern int osal_hrtimer_start(osal_hrtimer_t *phrtimer);
extern int osal_hrtimer_destory(osal_hrtimer_t *phrtimer);
extern int osal_timer_init(osal_timer_t *timer);
extern int osal_set_timer(osal_timer_t *timer, unsigned long interval); // ms
extern int osal_del_timer(osal_timer_t *timer);
extern int osal_timer_destory(osal_timer_t *timer);
extern unsigned long osal_msleep(unsigned int msecs);
extern void osal_udelay(unsigned int usecs);
extern void osal_mdelay(unsigned int msecs);
extern unsigned int osal_get_tickcount(void);
extern unsigned long long osal_sched_clock(void);
extern void osal_gettimeofday(osal_timeval_t *tv);
extern void osal_rtc_time_to_tm(unsigned long time, osal_rtc_time_t *tm);
extern void osal_rtc_tm_to_time(osal_rtc_time_t *tm, unsigned long *time);
extern int osal_rtc_valid_tm(struct osal_rtc_time *tm);
extern void osal_getjiffies(unsigned long long *pjiffies);
#define OSAL_O_ACCMODE 00000003
#define OSAL_O_RDONLY 00000000
#define OSAL_O_WRONLY 00000001
#define OSAL_O_RDWR 00000002
#define OSAL_O_CREAT 00000100
extern void *osal_klib_fopen(const char *filename, int flags, int mode);
extern void osal_klib_fclose(void *filp);
extern int osal_klib_fwrite(const char *buf, int len, void *filp);
extern int osal_klib_fread(char *buf, unsigned int len, void *filp);
// reboot
struct osal_notifier_block {
int (*notifier_call)(struct osal_notifier_block *nb, unsigned long action, void *data);
void *notifier_block;
};
typedef int (*osal_notifier_fn_t)(struct osal_notifier_block *nb, unsigned long action, void *data);
extern int osal_register_reboot_notifier(struct osal_notifier_block *nb);
extern int osal_unregister_reboot_notifier(struct osal_notifier_block *nb);
#include <stdarg.h>
#ifndef _OSAL_VA_LIST
#define _OSAL_VA_LIST
#define osal_va_list va_list
#define osal_va_arg(ap, T) va_arg(ap, T)
#define osal_va_end(ap) va_end(ap)
#define osal_va_start(ap, A) va_start(ap, A)
#endif /* va_arg */
#define NULL_STRING "NULL"
extern void osal_vprintk(const char *fmt, osal_va_list args);
extern int osal_vsnprintf(char *str, int size, const char *fmt, osal_va_list args);
#ifdef CONFIG_HISI_SNAPSHOT_BOOT
#ifndef OSAL_UMH_WAIT_PROC
#define OSAL_UMH_WAIT_PROC 2 /* wait for the process to complete */
#endif
extern int osal_call_usermodehelper_force(char *path, char **argv, char **envp, int wait);
#endif
int osal_platform_driver_register(void *drv);
void osal_platform_driver_unregister(void *drv);
void *osal_platform_get_resource_byname(void *dev, unsigned int type,
const char *name);
void *osal_platform_get_resource(void *dev, unsigned int type,
unsigned int num);
int osal_platform_get_irq(void *dev, unsigned int num);
int osal_platform_get_irq_byname(void *dev, const char *name);
#define osal_module_driver(osal_driver, osal_register, osal_unregister, ...) \
static int __init osal_driver##_init(void) \
{ \
return osal_register(&(osal_driver)); \
} \
module_init(osal_driver##_init); \
static void __exit osal_driver##_exit(void) \
{ \
osal_unregister(&(osal_driver)); \
} \
module_exit(osal_driver##_exit);
#define osal_module_platform_driver(platform_driver) \
osal_module_driver(platform_driver, osal_platform_driver_register, \
osal_platform_driver_unregister)
#endif

View File

@ -0,0 +1,48 @@
/*
* copyright (c) hisilicon technologies co., ltd. 2016-2019. all rights reserved.
* description: hi_serdes.h
* author: hisilicon multimedia software group
* create: 2019-05-17
*/
#ifndef __HI_SERDES_H__
#define __HI_SERDES_H__
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /*end of #ifdef __cplusplus*/
typedef unsigned int serdes_dev_t;
typedef enum
{
SERDES_MODE_4LANE_LINEAR = 0,
SERDES_MODE_4LANE_WDR,
SERDES_MODE_2LANE_LINEAR,
SERDES_MODE_2LANE_WDR,
SERDES_MODE_BUTT,
} serdes_mode_t;
typedef struct
{
serdes_dev_t devno; /* I2C_DEV */
serdes_mode_t serdes_mode;
unsigned char sendes_en;
unsigned char sensor_i2c_addr; /* serdes connected sensor's i2c addr */
} serdes_dev_attr_t;
#define HI_SERDES_IOC_MAGIC 'n'
/* init data lane, input mode, data type */
#define HI_SERDES_START _IOW(HI_SERDES_IOC_MAGIC, 0x01, serdes_dev_attr_t)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /*end of #ifdef __cplusplus*/
#endif /*end of #ifdef __HI_SERDES_H__*/

View File

@ -0,0 +1,106 @@
#ifndef _DRV_IOCTL_H
#define _DRV_IOCTL_H
/* ioctl command encoding: 32 bits total, command in lower 16 bits,
* size of the parameter structure in the lower 14 bits of the
* upper 16 bits.
* Encoding the size of the parameter structure in the ioctl request
* is useful for catching programs compiled with old versions
* and to avoid overwriting user space outside the user buffer area.
* The highest 2 bits are reserved for indicating the ``access mode''.
* NOTE: This limits the max parameter size to 16kB -1 !
*/
/*
* The following is for compatibility across the various Linux
* platforms. The generic ioctl numbering scheme doesn't really enforce
* a type field. De facto, however, the top 8 bits of the lower 16
* bits are indeed used as a type field, so we might just as well make
* this explicit here. Please be sure to use the decoding macros
* below from now on.
*/
#define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
/*
* Let any architecture override either of the following before
* including this file.
*/
#ifndef _IOC_SIZEBITS
#define _IOC_SIZEBITS 14
#endif
#ifndef _IOC_DIRBITS
#define _IOC_DIRBITS 2
#endif
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
/*
* Direction bits, which any architecture can choose to override
* before including this file.
*/
#ifndef _IOC_NONE
#define _IOC_NONE 0U
#endif
#ifndef _IOC_WRITE
#define _IOC_WRITE 1U
#endif
#ifndef _IOC_READ
#define _IOC_READ 2U
#endif
#define _IOC(dir, type, nr, size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
// #define _IOC_TYPECHECK(t) (sizeof(t))
#ifdef __CHECKER__
#define _IOC_TYPECHECK(t) (sizeof(t))
#else
/* provoke compile error for invalid uses of size argument */
extern unsigned int __invalid_size_argument_for_IOC;
#define _IOC_TYPECHECK(t) \
((sizeof(t) == sizeof(t[1]) && \
sizeof(t) < (1 << _IOC_SIZEBITS)) \
? sizeof(t) \
: __invalid_size_argument_for_IOC)
#endif
/* used to create numbers */
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
#endif /* _DRV_IOCTL_H */

View File

@ -0,0 +1,742 @@
#ifndef _OSAL_LIST_H
#define _OSAL_LIST_H
#define OSAL_NULL (0)
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct osal_list_head {
struct osal_list_head *next, *prev;
};
#define OSAL_LIST_HEAD_INIT(name) \
{ \
&(name), &(name) \
}
#define OSAL_LIST_HEAD(name) \
struct osal_list_head name = OSAL_LIST_HEAD_INIT(name)
static inline void OSAL_INIT_LIST_HEAD(struct osal_list_head *list)
{
list->next = list;
list->prev = list;
}
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void osal___list_add(struct osal_list_head *new,
struct osal_list_head *prev,
struct osal_list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void osal_list_add(struct osal_list_head *new, struct osal_list_head *head)
{
osal___list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void osal_list_add_tail(struct osal_list_head *new, struct osal_list_head *head)
{
osal___list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void osal___list_del(struct osal_list_head *prev, struct osal_list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void osal___list_del_entry(struct osal_list_head *entry)
{
osal___list_del(entry->prev, entry->next);
}
#define OSAL_LIST_POISON1 ((void *)0x00100100)
#define OSAL_LIST_POISON2 ((void *)0x00200200)
static inline void osal_list_del(struct osal_list_head *entry)
{
osal___list_del(entry->prev, entry->next);
entry->next = OSAL_LIST_POISON1;
entry->prev = OSAL_LIST_POISON2;
}
/**
* list_replace - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* If @old was empty, it will be overwritten.
*/
static inline void osal_list_replace(struct osal_list_head *old,
struct osal_list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
static inline void osal_list_replace_init(struct osal_list_head *old,
struct osal_list_head *new)
{
osal_list_replace(old, new);
OSAL_INIT_LIST_HEAD(old);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void osal_list_del_init(struct osal_list_head *entry)
{
osal___list_del_entry(entry);
OSAL_INIT_LIST_HEAD(entry);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void osal_list_move(struct osal_list_head *list, struct osal_list_head *head)
{
osal___list_del_entry(list);
osal_list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void osal_list_move_tail(struct osal_list_head *list,
struct osal_list_head *head)
{
osal___list_del_entry(list);
osal_list_add_tail(list, head);
}
/**
* list_is_last - tests whether @list is the last entry in list @head
* @list: the entry to test
* @head: the head of the list
*/
static inline int osal_list_is_last(const struct osal_list_head *list,
const struct osal_list_head *head)
{
return list->next == head;
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int osal_list_empty(const struct osal_list_head *head)
{
return head->next == head;
}
/**
* list_empty_careful - tests whether a list is empty and not being modified
* @head: the list to test
*
* Description:
* tests whether a list is empty _and_ checks that no other CPU might be
* in the process of modifying either member (next or prev)
*
* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.
*/
static inline int osal_list_empty_careful(const struct osal_list_head *head)
{
struct osal_list_head *next = head->next;
return (next == head) && (next == head->prev);
}
/**
* list_rotate_left - rotate the list to the left
* @head: the head of the list
*/
static inline void osal_list_rotate_left(struct osal_list_head *head)
{
struct osal_list_head *first;
if (!osal_list_empty(head)) {
first = head->next;
osal_list_move_tail(first, head);
}
}
/**
* list_is_singular - tests whether a list has just one entry.
* @head: the list to test.
*/
static inline int osal_list_is_singular(const struct osal_list_head *head)
{
return !osal_list_empty(head) && (head->next == head->prev);
}
static inline void osal___list_cut_position(struct osal_list_head *list,
struct osal_list_head *head, struct osal_list_head *entry)
{
struct osal_list_head *new_first = entry->next;
list->next = head->next;
list->next->prev = list;
list->prev = entry;
entry->next = list;
head->next = new_first;
new_first->prev = head;
}
/**
* list_cut_position - cut a list into two
* @list: a new list to add all removed entries
* @head: a list with entries
* @entry: an entry within head, could be the head itself
* and if so we won't cut the list
*
* This helper moves the initial part of @head, up to and
* including @entry, from @head to @list. You should
* pass on @entry an element you know is on @head. @list
* should be an empty list or a list you do not care about
* losing its data.
*
*/
static inline void osal_list_cut_position(struct osal_list_head *list,
struct osal_list_head *head, struct osal_list_head *entry)
{
if (osal_list_empty(head)) {
return;
}
if (osal_list_is_singular(head) &&
((head->next != entry) && (head != entry))) {
return;
}
if (entry == head) {
OSAL_INIT_LIST_HEAD(list);
} else {
osal___list_cut_position(list, head, entry);
}
}
static inline void osal___list_splice(const struct osal_list_head *list,
struct osal_list_head *prev,
struct osal_list_head *next)
{
struct osal_list_head *first = list->next;
struct osal_list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
/**
* list_splice - join two lists, this is designed for stacks
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void osal_list_splice(const struct osal_list_head *list,
struct osal_list_head *head)
{
if (!osal_list_empty(list)) {
osal___list_splice(list, head, head->next);
}
}
/**
* list_splice_tail - join two lists, each list being a queue
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void osal_list_splice_tail(struct osal_list_head *list,
struct osal_list_head *head)
{
if (!osal_list_empty(list)) {
osal___list_splice(list, head->prev, head);
}
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void osal_list_splice_init(struct osal_list_head *list,
struct osal_list_head *head)
{
if (!osal_list_empty(list)) {
osal___list_splice(list, head, head->next);
OSAL_INIT_LIST_HEAD(list);
}
}
/**
* list_splice_tail_init - join two lists and reinitialise the emptied list
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* Each of the lists is a queue.
* The list at @list is reinitialised
*/
static inline void osal_list_splice_tail_init(struct osal_list_head *list,
struct osal_list_head *head)
{
if (!osal_list_empty(list)) {
osal___list_splice(list, head->prev, head);
OSAL_INIT_LIST_HEAD(list);
}
}
#undef osal_offsetof
#ifdef __compiler_offsetof
#define osal_offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER)
#else
#define osal_offsetof(TYPE, MEMBER) ((int)(unsigned long)&((TYPE *)0)->MEMBER)
#endif
#define osal_container_of(ptr, type, member) ({ \
const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - osal_offsetof(type,member) ); })
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define osal_list_entry(ptr, type, member) \
osal_container_of(ptr, type, member)
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define osal_list_first_entry(ptr, type, member) \
osal_list_entry((ptr)->next, type, member)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define osal_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* __list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* This variant doesn't differ from list_for_each() any more.
* We don't do prefetching in either case.
*/
#define osal___list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define osal_list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define osal_list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define osal_list_for_each_prev_safe(pos, n, head) \
for (pos = (head)->prev, n = pos->prev; \
pos != (head); \
pos = n, n = pos->prev)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define osal_list_for_each_entry(pos, head, member) \
for (pos = osal_list_entry((head)->next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = osal_list_entry(pos->member.next, __typeof__(*pos), member))
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define osal_list_for_each_entry_reverse(pos, head, member) \
for (pos = osal_list_entry((head)->prev, __typeof__(*pos), member); \
&pos->member != (head); \
pos = osal_list_entry(pos->member.prev, __typeof__(*pos), member))
/**
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
* @pos: the type * to use as a start point
* @head: the head of the list
* @member: the name of the list_struct within the struct.
*
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
*/
#define osal_list_prepare_entry(pos, head, member) \
((pos) ?: osal_list_entry(head, __typeof__(*pos), member))
/**
* list_for_each_entry_continue - continue iteration over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Continue to iterate over list of given type, continuing after
* the current position.
*/
#define osal_list_for_each_entry_continue(pos, head, member) \
for (pos = osal_list_entry(pos->member.next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = osal_list_entry(pos->member.next, __typeof__(*pos), member))
/**
* list_for_each_entry_continue_reverse - iterate backwards from the given point
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Start to iterate over list of given type backwards, continuing after
* the current position.
*/
#define osal_list_for_each_entry_continue_reverse(pos, head, member) \
for (pos = osal_list_entry(pos->member.prev, __typeof__(*pos), member); \
&pos->member != (head); \
pos = osal_list_entry(pos->member.prev, __typeof__(*pos), member))
/**
* list_for_each_entry_from - iterate over list of given type from the current point
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate over list of given type, continuing from current position.
*/
#define osal_list_for_each_entry_from(pos, head, member) \
for (; &pos->member != (head); \
pos = osal_list_entry(pos->member.next, __typeof__(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define osal_list_for_each_entry_safe(pos, n, head, member) \
for (pos = osal_list_entry((head)->next, __typeof__(*pos), member), \
n = osal_list_entry(pos->member.next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = n, n = osal_list_entry(n->member.next, __typeof__(*n), member))
/**
* list_for_each_entry_safe_continue - continue list iteration safe against removal
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate over list of given type, continuing after current point,
* safe against removal of list entry.
*/
#define osal_list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = osal_list_entry(pos->member.next, __typeof__(*pos), member), \
n = osal_list_entry(pos->member.next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = n, n = osal_list_entry(n->member.next, __typeof__(*n), member))
/**
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate over list of given type from current point, safe against
* removal of list entry.
*/
#define osal_list_for_each_entry_safe_from(pos, n, head, member) \
for (n = osal_list_entry(pos->member.next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = n, n = osal_list_entry(n->member.next, __typeof__(*n), member))
/**
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* Iterate backwards over list of given type, safe against removal
* of list entry.
*/
#define osal_list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = osal_list_entry((head)->prev, __typeof__(*pos), member), \
n = osal_list_entry(pos->member.prev, __typeof__(*pos), member); \
&pos->member != (head); \
pos = n, n = osal_list_entry(n->member.prev, __typeof__(*n), member))
/**
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
* @pos: the loop cursor used in the list_for_each_entry_safe loop
* @n: temporary storage used in list_for_each_entry_safe
* @member: the name of the list_struct within the struct.
*
* list_safe_reset_next is not safe to use in general if the list may be
* modified concurrently (eg. the lock is dropped in the loop body). An
* exception to this is if the cursor element (pos) is pinned in the list,
* and list_safe_reset_next is called after re-taking the lock and before
* completing the current iteration of the loop body.
*/
#define osal_list_safe_reset_next(pos, n, member) \
n = osal_list_entry(pos->member.next, __typeof__(*pos), member)
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/
struct osal_hlist_node {
struct osal_hlist_node *next, **pprev;
};
struct osal_hlist_head {
struct osal_hlist_node *first;
};
#define OSAL_HLIST_HEAD_INIT \
{ \
.first = OSAL_NULL \
}
#define OSAL_HLIST_HEAD(name) struct osal_hlist_head name = { .first = OSAL_NULL }
#define INIT_OSAL_HLIST_HEAD(ptr) ((ptr)->first = OSAL_NULL)
static inline void INIT_OSAL_HLIST_NODE(struct osal_hlist_node *h)
{
h->next = OSAL_NULL;
h->pprev = OSAL_NULL;
}
static inline int osal_hlist_unhashed(const struct osal_hlist_node *h)
{
return !h->pprev;
}
static inline int osal_hlist_empty(const struct osal_hlist_head *h)
{
return !h->first;
}
static inline void osal___hlist_del(struct osal_hlist_node *n)
{
struct osal_hlist_node *next = n->next;
struct osal_hlist_node **pprev = n->pprev;
*pprev = next;
if (next) {
next->pprev = pprev;
}
}
static inline void osal_hlist_del(struct osal_hlist_node *n)
{
osal___hlist_del(n);
n->next = OSAL_LIST_POISON1;
n->pprev = OSAL_LIST_POISON2;
}
static inline void osal_hlist_del_init(struct osal_hlist_node *n)
{
if (!osal_hlist_unhashed(n)) {
osal___hlist_del(n);
INIT_OSAL_HLIST_NODE(n);
}
}
static inline void osal_hlist_add_head(struct osal_hlist_node *n, struct osal_hlist_head *h)
{
struct osal_hlist_node *first = h->first;
n->next = first;
if (first) {
first->pprev = &n->next;
}
h->first = n;
n->pprev = &h->first;
}
/* next must be != NULL */
static inline void osal_hlist_add_before(struct osal_hlist_node *n,
struct osal_hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}
static inline void osal_hlist_add_after(struct osal_hlist_node *n,
struct osal_hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;
if (next->next) {
next->next->pprev = &next->next;
}
}
/* after that we'll appear to be on some hlist and hlist_del will work */
static inline void osal_hlist_add_fake(struct osal_hlist_node *n)
{
n->pprev = &n->next;
}
/*
* Move a list from one list head to another. Fixup the pprev
* reference of the first entry if it exists.
*/
static inline void osal_hlist_move_list(struct osal_hlist_head *old,
struct osal_hlist_head *new)
{
new->first = old->first;
if (new->first) {
new->first->pprev = &new->first;
}
old->first = OSAL_NULL;
}
#define osal_hlist_entry(ptr, type, member) osal_container_of(ptr, type, member)
#define osal_hlist_for_each(pos, head) \
for (pos = (head)->first; pos; pos = pos->next)
#define osal_hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
/**
* hlist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define osal_hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && \
({ tpos = osal_hlist_entry(pos, __typeof__(*tpos), member); 1; }); \
pos = pos->next)
/**
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define osal_hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && \
({ tpos = osal_hlist_entry(pos, __typeof__(*tpos), member); 1; }); \
pos = pos->next)
/**
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define osal_hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && \
({ tpos = osal_hlist_entry(pos, __typeof__(*tpos), member); 1; }); \
pos = pos->next)
/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define osal_hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = osal_hlist_entry(pos, __typeof__(*tpos), member); 1; }); \
pos = n)
#endif

View File

@ -0,0 +1,51 @@
/*
* copyright (c) hisilicon technologies co., ltd. 2016-2019. all rights reserved.
* description: type.h
* author: hisilicon multimedia software group
* create: 2019-05-17
*/
#ifndef __TYPE_H__
#define __TYPE_H__
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */
/*----------------------------------------------*
* const defination *
*----------------------------------------------*/
#ifndef NULL
#define NULL 0L
#endif
#ifndef HI_FALSE
#define HI_FALSE 0
#endif
#ifndef HI_TRUE
#define HI_TRUE 1
#endif
#ifndef HI_SUCCESS
#define HI_SUCCESS 0
#endif
#ifndef HI_FAILURE
#define HI_FAILURE (-1)
#endif
typedef unsigned char HI_U8;
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* __TYPE_H__ */

View File

@ -0,0 +1,378 @@
/*
* copyright (c) hisilicon technologies co., ltd. 2016-2019. all rights reserved.
* description: serdes_comm.c
* author: hisilicon multimedia software group
* create: 2019-05-17
*/
#include <linux/i2c.h>
#include <asm/uaccess.h>
#ifndef __HuaweiLite__
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/miscdevice.h>
#else
#include "i2c.h"
#endif
#include "hi_serdes.h"
#include "serdes_comm.h"
#include "type.h"
#define SERDES_DEV_NAME0 "serdes0"
#define SERDES_DEV_NAME1 "serdes1"
#define SERDES_I2C_BUF_MAX_NUM 8
#define ONT_BYTE_EQUAL_BIT_NUM 8
unsigned char sensor_dev_addr[SERDES_MAX_NUM] = {0};
unsigned char serdes_init_flag[SERDES_MAX_NUM] = {0};
static struct i2c_client *g_serdes_client[SERDES_MAX_NUM];
#ifndef __HuaweiLite__
static struct i2c_board_info g_thine_info =
{
I2C_BOARD_INFO(THINE_DEVICE_TYPE, (THINE_DEVICE_ADDR >> 1)),
};
#endif
int serdes_i2c_write(unsigned char i2c_dev, unsigned char dev_addr,
unsigned int reg_addr, unsigned int reg_addr_num,
unsigned int data, unsigned int data_byte_num)
{
unsigned char tmp_buf[SERDES_I2C_BUF_MAX_NUM];
int ret = 0;
int idx = 0;
unsigned int try_count = 0;
struct i2c_client client;
if (i2c_dev >= SERDES_MAX_NUM) {
return HI_FAILURE;
}
if (g_serdes_client[i2c_dev] == NULL) {
return HI_FAILURE;
}
osal_memcpy(&client, g_serdes_client[i2c_dev], sizeof(struct i2c_client));
#ifdef __HuaweiLite__
client.addr = ((dev_addr >> 1) & 0xff);
/* reg_addr config */
if (reg_addr_num == 1) {
client.flags &= ~I2C_M_16BIT_REG;
tmp_buf[idx++] = reg_addr & 0xff;
} else {
client.flags |= I2C_M_16BIT_REG;
tmp_buf[idx++] = (reg_addr >> ONT_BYTE_EQUAL_BIT_NUM) & 0xff;
tmp_buf[idx++] = reg_addr & 0xff;
}
/* data config */
if (data_byte_num == 1) {
client.flags &= ~I2C_M_16BIT_DATA;
tmp_buf[idx++] = data & 0xff;
} else {
client.flags |= I2C_M_16BIT_DATA;
tmp_buf[idx++] = (data >> ONT_BYTE_EQUAL_BIT_NUM) & 0xff;
tmp_buf[idx++] = data & 0xff;
}
#else
client.addr = (dev_addr >> 1);
/* reg_addr config */
if (reg_addr_num == 1) {
tmp_buf[idx++] = reg_addr & 0xff;
} else {
tmp_buf[idx++] = (reg_addr >> ONT_BYTE_EQUAL_BIT_NUM) & 0xff;
tmp_buf[idx++] = reg_addr & 0xff;
}
/* data config */
if (data_byte_num == 1) {
tmp_buf[idx++] = data & 0xff;
} else {
tmp_buf[idx++] = (data >> ONT_BYTE_EQUAL_BIT_NUM) & 0xff;
tmp_buf[idx++] = data & 0xff;
}
#endif
while (1) {
ret = hi_i2c_master_send(&client, (const char *)tmp_buf, idx);
if (ret == idx) {
break;
}
#ifdef __HuaweiLite__
else if ((ret == -EAGAIN))
#else
else if ((ret == -EAGAIN) && (in_atomic() || irqs_disabled()))
#endif
{
try_count++;
if (try_count > 5) {
return HI_FAILURE;
}
} else {
osal_printk("[%s %d] hi_i2c_master_send error, reg_addr=0x%x, ret=%d.\n", __func__, __LINE__, reg_addr, ret);
return ret;
}
}
return HI_SUCCESS;
}
int serdes_i2c_read(unsigned char i2c_dev, const unsigned char dev_addr,
const unsigned int reg_addr, unsigned int *data)
{
int ret;
static struct i2c_msg msg[2];
unsigned char buffer[2];
struct i2c_client client;
if (i2c_dev >= SERDES_MAX_NUM) {
return HI_FAILURE;
}
if (g_serdes_client[i2c_dev] == NULL) {
return HI_FAILURE;
}
osal_memcpy(&client, g_serdes_client[i2c_dev], sizeof(struct i2c_client));
buffer[0] = reg_addr >> ONT_BYTE_EQUAL_BIT_NUM & 0xFF;
buffer[1] = reg_addr & 0xFF;
msg[0].addr = client.addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = buffer;
msg[1].addr = client.addr;
msg[1].flags = client.flags | I2C_M_RD;
msg[1].len = 1;
msg[1].buf = buffer;
ret = hi_i2c_transfer(client.adapter, msg, 2);
if (ret != 2) {
osal_printk("[%s %d] hi_i2c_transfer error, ret=%d.\n", __FUNCTION__, __LINE__, ret);
return HI_FAILURE;
}
*data = buffer[0];
return HI_SUCCESS;
}
static int check_serdes_dev_attr(serdes_dev_attr_t* p_attr)
{
if (p_attr->devno >= SERDES_MAX_NUM) {
osal_printk("invalid serdes_dev number(%d)!\n", p_attr->devno);
return HI_FAILURE;
}
if (p_attr->sendes_en != HI_TRUE && p_attr->sendes_en != HI_FALSE) {
osal_printk("invalid serdes_en(%d)!\n", p_attr->sendes_en);
return HI_FAILURE;
}
if (p_attr->serdes_mode < SERDES_MODE_4LANE_LINEAR ||
p_attr->serdes_mode >= SERDES_MODE_BUTT) {
osal_printk("invalid serdes_mode(%d)!\n", p_attr->serdes_mode);
return HI_FAILURE;
}
return HI_SUCCESS;
}
#ifdef __HuaweiLite__
static int serdes_ioctl(struct file *file, int cmd, unsigned long arg)
#else
static long serdes_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#endif
{
int ret;
serdes_dev_attr_t __user *argp = (serdes_dev_attr_t __user *)arg;
serdes_dev_attr_t serdes_dev_attr;
if (copy_from_user(&serdes_dev_attr, argp, sizeof(serdes_dev_attr_t))) {
return -EFAULT;
}
switch (cmd) {
case HI_SERDES_START:
ret = check_serdes_dev_attr(&serdes_dev_attr);
if (ret < 0) {
return ret;
}
sensor_dev_addr[serdes_dev_attr.devno] = serdes_dev_attr.sensor_i2c_addr;
if ((serdes_dev_attr.sendes_en == HI_TRUE) &&
(serdes_init_flag[serdes_dev_attr.devno] == HI_FALSE)) {
serdes_thine_init(serdes_dev_attr.devno, serdes_dev_attr.serdes_mode);
serdes_init_flag[serdes_dev_attr.devno] = HI_TRUE;
} else if ((serdes_dev_attr.sendes_en == HI_FALSE) &&
(serdes_init_flag[serdes_dev_attr.devno] == HI_TRUE)){
serdes_thine_exit(serdes_dev_attr.devno);
serdes_init_flag[serdes_dev_attr.devno] = HI_FALSE;
} else {
}
break;
default: {
osal_printk("kernel: no such serdes command %#x!\n", cmd);
return HI_FAILURE;
}
}
return HI_SUCCESS;
}
#ifdef __HuaweiLite__
static int serdes_open(struct file *file)
{
return 0;
}
static int serdes_close(struct file *file)
{
return 0;
}
const static struct file_operations_vfs serdes_fops = {
.open = serdes_open,
.close = serdes_close,
.ioctl = serdes_ioctl
};
static struct i2c_client g_serdes_client_obj[SERDES_MAX_NUM];
static struct i2c_client *hi_serdes_i2c_client_init(int i2c_dev)
{
int ret;
struct i2c_client *i2c_client0 = &g_serdes_client_obj[i2c_dev];
i2c_client0->addr = THINE_DEVICE_ADDR >> 1;
i2c_client0->flags = 0;
ret = client_attach(i2c_client0, i2c_dev);
if (ret) {
dprintf("fail to attach g_serdes_client!\n");
return NULL;
}
return &g_serdes_client_obj[i2c_dev];
}
int serdes_mod_init(void)
{
int i = 0;
int ret;
for (i = 0; i < SERDES_MAX_NUM; i++) {
g_serdes_client[i] = hi_serdes_i2c_client_init(i);
}
ret = register_driver("/dev/serdes0", &serdes_fops, 0666, 0);
if (ret) {
osal_printk("register serdes0 device failed with %#x!\n", ret);
return -1;
}
ret = register_driver("/dev/serdes1", &serdes_fops, 0666, 0);
if (ret) {
osal_printk("register serdes1 device failed with %#x!\n", ret);
return -1;
}
osal_printk("\n====> register serdes0_1 success.\n");
return HI_SUCCESS;
}
void serdes_mod_exit(void)
{
unregister_driver("/dev/serdes1");
unregister_driver("/dev/serdes0");
return;
}
#else
static int serdes_open(struct inode *inode, struct file *file)
{
return 0;
}
static int serdes_close(struct inode *inode, struct file *file)
{
return 0;
}
static struct file_operations serdes_fops = {
.owner = THIS_MODULE,
.open = serdes_open,
.release = serdes_close,
.unlocked_ioctl = serdes_ioctl,
};
static struct miscdevice serdes_dev0 = {
.minor = MISC_DYNAMIC_MINOR,
.name = SERDES_DEV_NAME0,
.fops = &serdes_fops,
};
static struct miscdevice serdes_dev1 = {
.minor = MISC_DYNAMIC_MINOR,
.name = SERDES_DEV_NAME1,
.fops = &serdes_fops,
};
int serdes_mod_init(void)
{
int i;
int ret;
struct i2c_adapter *i2c_adapter;
for (i = 0; i < SERDES_MAX_NUM; i++) {
i2c_adapter = i2c_get_adapter(i);
if (i2c_adapter == NULL) {
osal_printk("i2c_get_adapter error!\n");
return HI_FAILURE;
}
g_serdes_client[i] = i2c_new_device(i2c_adapter, &g_thine_info);
i2c_put_adapter(i2c_adapter);
}
ret = misc_register(&serdes_dev0);
if (ret != HI_SUCCESS) {
osal_printk("kernel: register serdes_0 device failed!\n");
return HI_FAILURE;
}
ret = misc_register(&serdes_dev1);
if (ret != HI_SUCCESS) {
osal_printk("kernel: register serdes_1 device failed!\n");
return HI_FAILURE;
}
return HI_SUCCESS;
}
void serdes_mod_exit(void)
{
int i;
for (i = 0; i < SERDES_MAX_NUM; i++) {
i2c_unregister_device(g_serdes_client[i]);
}
misc_deregister(&serdes_dev1);
misc_deregister(&serdes_dev0);
return;
}
module_init(serdes_mod_init);
module_exit(serdes_mod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hisilicon");
#endif

View File

@ -0,0 +1,31 @@
/*
* copyright (c) hisilicon technologies co., ltd. 2016-2019. all rights reserved.
* description: serdes_comm.h
* author: hisilicon multimedia software group
* create: 2019-05-17
*/
#ifndef __HI_SERDES_COMM_H__
#define __HI_SERDES_COMM_H__
#include "hi_osal.h"
#define THINE_DEVICE_TYPE "241a-242"
#define THINE_DEVICE_ADDR 0x16
#define SERDES_MAX_NUM 2
extern unsigned char sensor_dev_addr[SERDES_MAX_NUM];
int serdes_i2c_write(unsigned char i2c_dev, unsigned char dev_addr,
unsigned int reg_addr, unsigned int reg_addr_num,
unsigned int data, unsigned int data_byte_num);
int serdes_i2c_read(unsigned char i2c_dev, const unsigned char dev_addr,
const unsigned int reg_addr, unsigned int *data);
void serdes_thine_init(int i2c_dev, serdes_mode_t serdes_mode);
void serdes_thine_exit(int i2c_dev);
#endif // __HI_SERDES_COMM_H__

View File

@ -0,0 +1,703 @@
/*
* copyright (c) hisilicon technologies co., ltd. 2016-2019. all rights reserved.
* description: thine_241a242_serdes.c
* author: hisilicon multimedia software group
* create: 2019-05-17
*/
#include "thine_241a242_serdes.h"
static inline void delay_us(const int us)
{
udelay(us);
return;
}
/* for 242 */
void write_serdes_rx_register(unsigned char i2c_dev, const unsigned int reg_addr, const unsigned int data)
{
unsigned int reg_addr_num = 2;
unsigned int data_byte_num = 1;
unsigned char dev_addr = THINE_DEVICE_ADDR;
serdes_i2c_write(i2c_dev, dev_addr, reg_addr, reg_addr_num, data, data_byte_num);
return;
}
void write_serdes_rx_1bype_register(unsigned char i2c_dev, const unsigned int reg_addr, const unsigned int data)
{
unsigned int reg_addr_num = 1;
unsigned int data_byte_num = 1;
unsigned char dev_addr = THINE_DEVICE_ADDR;
serdes_i2c_write(i2c_dev, dev_addr, reg_addr, reg_addr_num, data, data_byte_num);
return;
}
int read_serdes_rx_register(unsigned char i2c_dev, const unsigned int reg_addr)
{
unsigned int r_data = 0;
unsigned char dev_addr = (THINE_DEVICE_ADDR + 1);
serdes_i2c_read(i2c_dev, dev_addr, reg_addr, &r_data);
return r_data;
}
/* for 241 */
void write_serdes_tx_1bype_register(unsigned char i2c_dev, unsigned int reg_addr, const unsigned int data)
{
unsigned int reg_addr_num = 1;
unsigned int data_byte_num = 1;
unsigned char dev_addr = (sensor_dev_addr[i2c_dev] << 1);
serdes_i2c_write(i2c_dev, dev_addr, reg_addr, reg_addr_num, data, data_byte_num);
return;
}
void write_serdes_tx_2bype_register(unsigned char i2c_dev, const unsigned int reg_addr, const unsigned int data)
{
unsigned int reg_addr_num = 2;
unsigned int data_byte_num = 1;
unsigned char dev_addr = (sensor_dev_addr[i2c_dev] << 1);
serdes_i2c_write(i2c_dev, dev_addr, reg_addr, reg_addr_num, data, data_byte_num);
return;
}
void set_serdes_data_rate(unsigned char i2c_dev, serdes_mode_t serdes_mode)
{
#if SERDES_DEBUG
int result = 0;
#endif
if (serdes_mode == SERDES_MODE_4LANE_LINEAR) {
write_serdes_rx_register(i2c_dev, 0x1609, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1609);
osal_printk("read 242 0x1609: 0x%x, should be 0x00\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160A, 0x0C);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160A);
osal_printk("read 242 0x160A: 0x%x, should be 0x0C\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160B, 0x03);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160B);
osal_printk("read 242 0x160B: 0x%x, should be 0x03\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160C, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160C);
osal_printk("read 242 0x160C: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160D, 0x0C);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160D);
osal_printk("read 242 0x160D: 0x%x, should be 0x0C\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160E, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160E);
osal_printk("read 242 0x160E: 0x%x, should be 0x00\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160F, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160F);
osal_printk("read 242 0x160F: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1610, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1610);
osal_printk("read 242 0x1610: 0x%x, should be 0x00\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1611, 0x02);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1611);
osal_printk("read 242 0x1611: 0x%x, should be 0x02\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1612, 0x02);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1612);
osal_printk("read 242 0x1612: 0x%x, should be 0x02\n", result);
#endif
} else if ((serdes_mode == SERDES_MODE_2LANE_LINEAR) ||
(serdes_mode == SERDES_MODE_4LANE_WDR)) {
write_serdes_rx_register(i2c_dev, 0x1609, 0x03);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1609);
osal_printk("read 242 0x1609: 0x%x, should be 0x03\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160A, 0x0F);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160A);
osal_printk("read 242 0x160A: 0x%x, should be 0x0F\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160B, 0x05);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160B);
osal_printk("read 242 0x160B: 0x%x, should be 0x05\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160C, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160C);
osal_printk("read 242 0x160C: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160D, 0x0A);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160D);
osal_printk("read 242 0x160D: 0x%x, should be 0x0A\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160E, 0x02);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160E);
osal_printk("read 242 0x160E: 0x%x, should be 0x02\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160F, 0x02);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160F);
osal_printk("read 242 0x160F: 0x%x, should be 0x02\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1610, 0x03);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1610);
osal_printk("read 242 0x1610: 0x%x, should be 0x03\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1611, 0x02);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1611);
osal_printk("read 242 0x1611: 0x%x, should be 0x02\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1612, 0x04);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1612);
osal_printk("read 242 0x1612: 0x%x, should be 0x04\n", result);
#endif
} else if (serdes_mode == SERDES_MODE_2LANE_WDR) {
write_serdes_rx_register(i2c_dev, 0x1609, 0x04);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1609);
osal_printk("read 242 0x1609: 0x%x, should be 0x04\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160A, 0x23);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160A);
osal_printk("read 242 0x160A: 0x%x, should be 0x23\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160B, 0x08);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160B);
osal_printk("read 242 0x160B: 0x%x, should be 0x08\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160C, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160C);
osal_printk("read 242 0x160C: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160D, 0x11);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160D);
osal_printk("read 242 0x160D: 0x%x, should be 0x11\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160E, 0x09);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160E);
osal_printk("read 242 0x160E: 0x%x, should be 0x09\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x160F, 0x06);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x160F);
osal_printk("read 242 0x160F: 0x%x, should be 0x06\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1610, 0x06);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1610);
osal_printk("read 242 0x1610: 0x%x, should be 0x06\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1611, 0x10);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1611);
osal_printk("read 242 0x1611: 0x%x, should be 0x10\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1612, 0x08);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1612);
osal_printk("read 242 0x1612: 0x%x, should be 0x08\n", result);
#endif
}
}
void get_serdes_cfg(serdes_mode_t serdes_mode, serdes_config *cfg)
{
if (serdes_mode == SERDES_MODE_4LANE_LINEAR) {
osal_memcpy(cfg, &imx307_4_lane_linear_12_bit_30_fps_cfg, sizeof(serdes_config));
} else if (serdes_mode == SERDES_MODE_4LANE_WDR) {
osal_memcpy(cfg, &imx307_4_lane_wdr_12_bit_30_fps_cfg, sizeof(serdes_config));
} else if (serdes_mode == SERDES_MODE_2LANE_LINEAR) {
osal_memcpy(cfg, &imx307_2_lane_linear_12_bit_30_fps_cfg, sizeof(serdes_config));
} else {
osal_memcpy(cfg, &imx307_2_lane_wdr_12_bit_30_fps_cfg, sizeof(serdes_config));
}
}
void serdes_241_242_init(unsigned char i2c_dev, serdes_mode_t serdes_mode)
{
int i = 0;
serdes_config cfg;
#if SERDES_DEBUG
int result = 0;
#endif
get_serdes_cfg(serdes_mode, &cfg);
/*---------------------------------------------------------
step1: THCV242 sub-link mode : THCV241A ID
------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0050, 0x34);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0050);
osal_printk("read 242 0x0050: 0x%x, should be 0x34\n", result);
#endif
/*---------------------------------------------------------
step1: THCV242 sub-link mode : pass throuth mode
------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0004, 0x03);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0004);
osal_printk("read 242 0x0004: 0x%x, should be 0x3\n", result);
#endif
/*---------------------------------------------------------
step2: THCV242 sub link en/pol : lane 0 enable polling off
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0010, 0x10); // polling off
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0010);
osal_printk("read 242 0x0010: 0x%x, should be 0x10\n", result);
#endif
/*---------------------------------------------------------
step3: THCV242 sub link power on
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x1704, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1704);
osal_printk("read 242 0x1704: 0x%x, should be 0x1\n", result);
#endif
/*---------------------------------------------------------
step4: THCV242 sub link tx term 50ohm
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0102, 0x02); // 50ohm
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0102);
osal_printk("read 242 0x0102: 0x%x, should be 0x2\n", result);
#endif
/*---------------------------------------------------------
step5: THCV242 sub link tx drv 12ma
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0103, 0x02); // 12m_a
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0103);
osal_printk("read 242 0x0103: 0x%x, should be 0x2\n", result);
#endif
/*---------------------------------------------------------
step6: THCV242 sub link rx term : 50ohm
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0104, 0x02); // 50ohm
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0104);
osal_printk("read 242 0x0104: 0x%x, should be 0x2\n", result);
#endif
/*---------------------------------------------------------
step7: THCV242 rx drv : 12ma
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0105, 0x02); // 12mA
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0105);
osal_printk("read 242 0x0105: 0x%x, should be 0x2\n", result);
#endif
/*---------------------------------------------------------
step8: THCV242 reserved setting : key is unlocked
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0100, 0x03);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0100);
osal_printk("read 242 0x0100: 0x%x, should be 0x3\n", result);
#endif
/*---------------------------------------------------------
step9: THCV242 reserved setting : key2 is unlocked
------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x010F, 0x25);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x010F);
osal_printk("read 242 0x010F: 0x%x, should be 0x25\n", result);
#endif
/*---------------------------------------------------------
step10: THCV242 reserved setting : sub link width
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x010A, 0x15); // 0x15 -> 0x18 -> 0x15
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x010A);
osal_printk("read 242 0x010A: 0x%x, should be 0x15\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x0031, 0x02);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0031);
osal_printk("read 242 0x0031: 0x%x, should be 0x2\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x0032, 0x10);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0032);
osal_printk("read 242 0x0032: 0x%x, should be 0x10\n", result);
#endif
/*---------------------------------------------------------
step13: THCV241 bank is 00
---------------------------------------------------------*/
write_serdes_tx_2bype_register(i2c_dev, 0x00FE, 0x11);
write_serdes_rx_register(i2c_dev, 0x0032, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0032);
osal_printk("read 242 0x0032: 0x%x, should be 0x00\n", result);
#endif
/*---------------------------------------------------------
step14: THCV241 sub link tx term / drv setting:50ohm 12ma
---------------------------------------------------------*/
write_serdes_tx_1bype_register(i2c_dev, 0x00F2, 0x22); // 50ohm/12mA
write_serdes_tx_1bype_register(i2c_dev, 0x00F3, 0x22); // 50ohm/12mA
/*---------------------------------------------------------
step15: THCV241 reserved setting : key is unlocked
---------------------------------------------------------*/
write_serdes_tx_1bype_register(i2c_dev, 0x00F0, 0x03);
/*---------------------------------------------------------
THCV241 reserved setting : key 2 is unlocked
---------------------------------------------------------*/
write_serdes_tx_1bype_register(i2c_dev, 0x00FF, 0x19);
/*---------------------------------------------------------
step16: THCV241 reserved setting : sub link width
---------------------------------------------------------*/
write_serdes_tx_1bype_register(i2c_dev, 0x00F6, 0x18); // 0x15
/*---------------------------------------------------------
step16: THCV241 I2C freq 400k_hz
---------------------------------------------------------*/
write_serdes_tx_1bype_register(i2c_dev, 0x00C9, 0x05);
write_serdes_tx_1bype_register(i2c_dev, 0x00CA, 0x05);
/*---------------------------------------------------------
step17: THCV242 sub link en/pol : lane 0 enable polling on
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x0010, 0x11);
/*---------------------------------------------------------
step18: THCV241 bank is 10
---------------------------------------------------------*/
write_serdes_tx_1bype_register(i2c_dev, 0x00FE, 0x21);
write_serdes_tx_1bype_register(i2c_dev, 0x002C, 0x01);
write_serdes_tx_1bype_register(i2c_dev, 0x002D, cfg.pll_value[i]);
i += 1;
write_serdes_tx_1bype_register(i2c_dev, 0x0076, 0x10);
write_serdes_tx_1bype_register(i2c_dev, 0x0000, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0x0001, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0x000F, 0x01);
write_serdes_tx_1bype_register(i2c_dev, 0x0011, cfg.pll_value[i]);
i += 1;
write_serdes_tx_1bype_register(i2c_dev, 0x0012, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0x0013, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0x0014, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0x0015, cfg.pll_value[i]);
i += 1;
write_serdes_tx_1bype_register(i2c_dev, 0x0016, 0x01);
write_serdes_tx_1bype_register(i2c_dev, 0x002B, 0x07);
write_serdes_tx_1bype_register(i2c_dev, 0x002F, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0x0005, 0x01);
write_serdes_tx_1bype_register(i2c_dev, 0x0006, 0x01);
write_serdes_tx_1bype_register(i2c_dev, 0x0027, 0x00);
/*---------------------------------------------------------
step19: THCV242
---------------------------------------------------------*/
write_serdes_rx_register(i2c_dev, 0x1010, 0xA1);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1010);
osal_printk("read 242 0x1010: 0x%x, should be 0xa1\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1021, 0x20);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1021);
osal_printk("read 242 0x1021: 0x%x, should be 0x20\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1022, cfg.pll_value[i]);
i += 1;
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1022);
osal_printk("read 242 0x1022: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1023, cfg.pll_value[i]);
i += 1;
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1023);
osal_printk("read 242 0x1023: 0x%x, should be 0x41--4L linear, 0x21--4L wdr\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1024, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1024);
osal_printk("read 242 0x1024: 0x%x, should be 0x00\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1025, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1025);
osal_printk("read 242 0x1025: 0x%x, should be 0x00\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1026, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1026);
osal_printk("read 242 0x1026: 0x%x, should be 0x00\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1027, 0x07);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1027);
osal_printk("read 242 0x1027: 0x%x, should be 0x07\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1028, cfg.pll_value[i]);
i += 1;
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1028);
osal_printk("read 242 0x1028: 0x%x, should be 0x00--4lane, 0x2--2lane\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1030, 0x00);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1030);
osal_printk("read 242 0x1030: 0x%x, should be 0x00\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1100, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1100);
osal_printk("read 242 0x1100: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1101, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1101);
osal_printk("read 242 0x1101: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1102, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1102);
osal_printk("read 242 0x1102: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1600, 0x1A);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1600);
osal_printk("read 242 0x1600: 0x%x, should be 0x1a\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1605, cfg.pll_value[i]);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1605);
osal_printk("read 242 0x1605: 0x%x, should be 0x2b--4lane, 0x29--2lane\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1606, 0x45);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1606);
osal_printk("read 242 0x1606: 0x%x, should be 0x45\n", result);
#endif
set_serdes_data_rate(i2c_dev, serdes_mode);
write_serdes_rx_register(i2c_dev, 0x1704, 0x11);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1704);
osal_printk("read 242 0x1704: 0x%x, should be 0x11\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x1703, 0x01);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x1703);
osal_printk("read 242 0x1703: 0x%x, should be 0x01\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x0032, 0x10);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0032);
osal_printk("read 242 0x0032: 0x%x, should be 0x10\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x0040, 0x1A);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0040);
osal_printk("read 242 0x0040: 0x%x, should be 0x1a\n", result);
#endif
write_serdes_rx_register(i2c_dev, 0x0041, 0x1A);
#if SERDES_DEBUG
result = read_serdes_rx_register(i2c_dev, 0x0041);
osal_printk("read 242 0x0041: 0x%x, should be 0x1a\n", result);
#endif
return;
}
void serdes_242_reset(unsigned char i2c_dev)
{
write_serdes_rx_register(i2c_dev, 0x1701, 0x3F);
write_serdes_rx_register(i2c_dev, 0x1702, 0x01); // SW reset
write_serdes_rx_register(i2c_dev, 0x1703, 0x00); // PLL power down
write_serdes_rx_register(i2c_dev, 0x1704, 0x00); // Vx1HS Sub-Link power down
write_serdes_rx_register(i2c_dev, 0x0050, 0x34);
write_serdes_rx_register(i2c_dev, 0x0004, 0x03);
write_serdes_rx_register(i2c_dev, 0x0010, 0x10);
write_serdes_rx_register(i2c_dev, 0x1704, 0x01); // Vx1HS Sub-Link power on
write_serdes_rx_register(i2c_dev, 0x0102, 0x02);
write_serdes_rx_register(i2c_dev, 0x0103, 0x02);
write_serdes_rx_register(i2c_dev, 0x0104, 0x02);
write_serdes_rx_register(i2c_dev, 0x0105, 0x02);
write_serdes_rx_register(i2c_dev, 0x0100, 0x03);
write_serdes_rx_register(i2c_dev, 0x010F, 0x25);
write_serdes_rx_register(i2c_dev, 0x010A, 0x15);
}
void serdes_241a_reset(unsigned char i2c_dev)
{
write_serdes_rx_1bype_register(i2c_dev, 0x0031, 0x02);
write_serdes_rx_1bype_register(i2c_dev, 0x0032, 0x00); // 1byte address, 1byte data access
write_serdes_tx_1bype_register(i2c_dev, 0x00FE, 0x21); // THCV241 bank is 10
write_serdes_tx_1bype_register(i2c_dev, 0x0005, 0x00); // PLL Soft Reset Active
write_serdes_tx_1bype_register(i2c_dev, 0x0006, 0x00); // Vx1HS Soft Reset Active
write_serdes_tx_1bype_register(i2c_dev, 0x0021, 0x00); // MIPI Logic Reset
write_serdes_tx_1bype_register(i2c_dev, 0x0022, 0x00); // Logic Reset
write_serdes_tx_1bype_register(i2c_dev, 0x0023, 0x00); // MIPI Clock Reset
delay_us(1000);
write_serdes_tx_1bype_register(i2c_dev, 0x0021, 0x01); // MIPI Logic Reset
write_serdes_tx_1bype_register(i2c_dev, 0x0022, 0x01); // Logic Reset
write_serdes_tx_1bype_register(i2c_dev, 0x0023, 0x01); // MIPI Clock Reset
write_serdes_tx_1bype_register(i2c_dev, 0x00FE, 0x00);
}
void serdes_241_242_exit(unsigned char i2c_dev)
{
serdes_242_reset(i2c_dev);
serdes_241a_reset(i2c_dev);
}
void serdes_thine_init(int i2c_dev, serdes_mode_t serdes_mode)
{
serdes_241_242_init(i2c_dev, serdes_mode);
}
void serdes_thine_exit(int i2c_dev)
{
serdes_241_242_exit(i2c_dev);
}
void serdes_reset_unreset_sensor(unsigned char i2c_dev, int reset)
{
const unsigned int tmp = reset ? 0x00 : 0x30; // 10/11 -> 00/30
write_serdes_rx_register(i2c_dev, 0x0032, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0xFE, 0x21);
write_serdes_tx_1bype_register(i2c_dev, 0x3E, tmp);
write_serdes_rx_register(i2c_dev, 0x0032, 0x10);
}
EXPORT_SYMBOL(serdes_reset_unreset_sensor);
void serdes_enable_disable_sensor_clock(unsigned char i2c_dev, int enable)
{
const unsigned int tmp = enable ? 0x10 : 0x50;
write_serdes_rx_register(i2c_dev, 0x0032, 0x00);
write_serdes_tx_1bype_register(i2c_dev, 0xFE, 0x21);
write_serdes_tx_1bype_register(i2c_dev, 0x76, tmp);
write_serdes_rx_register(i2c_dev, 0x0032, 0x10);
}
EXPORT_SYMBOL(serdes_enable_disable_sensor_clock);

View File

@ -0,0 +1,45 @@
/*
* copyright (c) hisilicon technologies co., ltd. 2016-2019. all rights reserved.
* description: thine_241a242_serdes.h
* author: hisilicon multimedia software group
* create: 2019-05-17
*/
#ifndef __THINE_241A242_SERDES_H__
#define __THINE_241A242_SERDES_H__
#include <linux/delay.h>
#include "hi_serdes.h"
#include "serdes_comm.h"
#include "type.h"
#define SERDES_DEBUG 0
#define THINE_PLL_VALUE_NUM 7
typedef struct
{
HI_U8 pll_value[THINE_PLL_VALUE_NUM];
} serdes_config;
serdes_config imx307_4_lane_linear_12_bit_30_fps_cfg =
{
.pll_value = {0x13, 0x1b, 0x66, 0x01, 0x41, 0x00, 0x2b},
};
serdes_config imx307_4_lane_wdr_12_bit_30_fps_cfg =
{
.pll_value = {0x13, 0x18, 0x44, 0x02, 0x21, 0x00, 0x2b},
};
serdes_config imx307_2_lane_linear_12_bit_30_fps_cfg =
{
.pll_value = {0x11, 0x1b, 0x66, 0x01, 0x21, 0x02, 0x29},
};
serdes_config imx307_2_lane_wdr_12_bit_30_fps_cfg =
{
.pll_value = {0x11, 0x18, 0x44, 0x02, 0x11, 0x02, 0x29},
};
#endif /* end of #ifdef __THINE_241A242_SERDES_H__ */