From 163f9eb95a10371ead59b62087e0d4e7ce53112e Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 21 Jan 2015 20:03:40 +0000 Subject: debugfs: Provide a file creation function that also takes an initial size Provide a file creation function that also takes an initial size so that the caller doesn't have to set i_size, thus meaning that we don't have to call deal with ->d_inode in the callers. Signed-off-by: David Howells --- include/linux/debugfs.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include') diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index ea149a24a1f2..cb25af461054 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -51,6 +51,11 @@ struct dentry *debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); +struct dentry *debugfs_create_file_size(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops, + loff_t file_size); + struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, @@ -129,6 +134,14 @@ static inline struct dentry *debugfs_create_file(const char *name, umode_t mode, return ERR_PTR(-ENODEV); } +static inline struct dentry *debugfs_create_file_size(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops, + loff_t file_size) +{ + return ERR_PTR(-ENODEV); +} + static inline struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) { -- cgit v1.2.3 From 4282d60689d4f21b40692029080440cc58e8a17d Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Tue, 20 Jan 2015 11:36:55 -0500 Subject: tracefs: Add new tracefs file system Add a separate file system to handle the tracing directory. Currently it is part of debugfs, but that is starting to show its limits. One thing is that in order to access the tracing infrastructure, you need to mount debugfs. As that includes debugging from all sorts of sub systems in the kernel, it is not considered advisable to mount such an all encompassing debugging system. Having the tracing system in its own file systems gives access to the tracing sub system without needing to include all other systems. Another problem with tracing using the debugfs system is that the instances use mkdir to create sub buffers. debugfs does not support mkdir from userspace so to implement it, special hacks were used. By controlling the file system that the tracing infrastructure uses, this can be properly done without hacks. Signed-off-by: Steven Rostedt --- fs/Makefile | 1 + fs/tracefs/Makefile | 4 + fs/tracefs/inode.c | 522 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/tracefs.h | 41 ++++ include/uapi/linux/magic.h | 2 + 5 files changed, 570 insertions(+) create mode 100644 fs/tracefs/Makefile create mode 100644 fs/tracefs/inode.c create mode 100644 include/linux/tracefs.h (limited to 'include') diff --git a/fs/Makefile b/fs/Makefile index bedff48e8fdc..d244b8d973ac 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_HOSTFS) += hostfs/ obj-$(CONFIG_HPPFS) += hppfs/ obj-$(CONFIG_CACHEFILES) += cachefiles/ obj-$(CONFIG_DEBUG_FS) += debugfs/ +obj-$(CONFIG_TRACING) += tracefs/ obj-$(CONFIG_OCFS2_FS) += ocfs2/ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ diff --git a/fs/tracefs/Makefile b/fs/tracefs/Makefile new file mode 100644 index 000000000000..82fa35b656c4 --- /dev/null +++ b/fs/tracefs/Makefile @@ -0,0 +1,4 @@ +tracefs-objs := inode.o + +obj-$(CONFIG_TRACING) += tracefs.o + diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c new file mode 100644 index 000000000000..5b1547a452d8 --- /dev/null +++ b/fs/tracefs/inode.c @@ -0,0 +1,522 @@ +/* + * inode.c - part of tracefs, a pseudo file system for activating tracing + * + * Based on debugfs by: Greg Kroah-Hartman + * + * Copyright (C) 2014 Red Hat Inc, author: Steven Rostedt + * + * 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. + * + * tracefs is the file system that is used by the tracing infrastructure. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRACEFS_DEFAULT_MODE 0700 + +static struct vfsmount *tracefs_mount; +static int tracefs_mount_count; +static bool tracefs_registered; + +static ssize_t default_read_file(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t default_write_file(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return count; +} + +static const struct file_operations tracefs_file_operations = { + .read = default_read_file, + .write = default_write_file, + .open = simple_open, + .llseek = noop_llseek, +}; + +static struct inode *tracefs_get_inode(struct super_block *sb) +{ + struct inode *inode = new_inode(sb); + if (inode) { + inode->i_ino = get_next_ino(); + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + } + return inode; +} + +struct tracefs_mount_opts { + kuid_t uid; + kgid_t gid; + umode_t mode; +}; + +enum { + Opt_uid, + Opt_gid, + Opt_mode, + Opt_err +}; + +static const match_table_t tokens = { + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_mode, "mode=%o"}, + {Opt_err, NULL} +}; + +struct tracefs_fs_info { + struct tracefs_mount_opts mount_opts; +}; + +static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts) +{ + substring_t args[MAX_OPT_ARGS]; + int option; + int token; + kuid_t uid; + kgid_t gid; + char *p; + + opts->mode = TRACEFS_DEFAULT_MODE; + + while ((p = strsep(&data, ",")) != NULL) { + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_uid: + if (match_int(&args[0], &option)) + return -EINVAL; + uid = make_kuid(current_user_ns(), option); + if (!uid_valid(uid)) + return -EINVAL; + opts->uid = uid; + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return -EINVAL; + gid = make_kgid(current_user_ns(), option); + if (!gid_valid(gid)) + return -EINVAL; + opts->gid = gid; + break; + case Opt_mode: + if (match_octal(&args[0], &option)) + return -EINVAL; + opts->mode = option & S_IALLUGO; + break; + /* + * We might like to report bad mount options here; + * but traditionally tracefs has ignored all mount options + */ + } + } + + return 0; +} + +static int tracefs_apply_options(struct super_block *sb) +{ + struct tracefs_fs_info *fsi = sb->s_fs_info; + struct inode *inode = sb->s_root->d_inode; + struct tracefs_mount_opts *opts = &fsi->mount_opts; + + inode->i_mode &= ~S_IALLUGO; + inode->i_mode |= opts->mode; + + inode->i_uid = opts->uid; + inode->i_gid = opts->gid; + + return 0; +} + +static int tracefs_remount(struct super_block *sb, int *flags, char *data) +{ + int err; + struct tracefs_fs_info *fsi = sb->s_fs_info; + + sync_filesystem(sb); + err = tracefs_parse_options(data, &fsi->mount_opts); + if (err) + goto fail; + + tracefs_apply_options(sb); + +fail: + return err; +} + +static int tracefs_show_options(struct seq_file *m, struct dentry *root) +{ + struct tracefs_fs_info *fsi = root->d_sb->s_fs_info; + struct tracefs_mount_opts *opts = &fsi->mount_opts; + + if (!uid_eq(opts->uid, GLOBAL_ROOT_UID)) + seq_printf(m, ",uid=%u", + from_kuid_munged(&init_user_ns, opts->uid)); + if (!gid_eq(opts->gid, GLOBAL_ROOT_GID)) + seq_printf(m, ",gid=%u", + from_kgid_munged(&init_user_ns, opts->gid)); + if (opts->mode != TRACEFS_DEFAULT_MODE) + seq_printf(m, ",mode=%o", opts->mode); + + return 0; +} + +static const struct super_operations tracefs_super_operations = { + .statfs = simple_statfs, + .remount_fs = tracefs_remount, + .show_options = tracefs_show_options, +}; + +static int trace_fill_super(struct super_block *sb, void *data, int silent) +{ + static struct tree_descr trace_files[] = {{""}}; + struct tracefs_fs_info *fsi; + int err; + + save_mount_options(sb, data); + + fsi = kzalloc(sizeof(struct tracefs_fs_info), GFP_KERNEL); + sb->s_fs_info = fsi; + if (!fsi) { + err = -ENOMEM; + goto fail; + } + + err = tracefs_parse_options(data, &fsi->mount_opts); + if (err) + goto fail; + + err = simple_fill_super(sb, TRACEFS_MAGIC, trace_files); + if (err) + goto fail; + + sb->s_op = &tracefs_super_operations; + + tracefs_apply_options(sb); + + return 0; + +fail: + kfree(fsi); + sb->s_fs_info = NULL; + return err; +} + +static struct dentry *trace_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + return mount_single(fs_type, flags, data, trace_fill_super); +} + +static struct file_system_type trace_fs_type = { + .owner = THIS_MODULE, + .name = "tracefs", + .mount = trace_mount, + .kill_sb = kill_litter_super, +}; +MODULE_ALIAS_FS("tracefs"); + +static struct dentry *start_creating(const char *name, struct dentry *parent) +{ + struct dentry *dentry; + int error; + + pr_debug("tracefs: creating file '%s'\n",name); + + error = simple_pin_fs(&trace_fs_type, &tracefs_mount, + &tracefs_mount_count); + if (error) + return ERR_PTR(error); + + /* If the parent is not specified, we create it in the root. + * We need the root dentry to do this, which is in the super + * block. A pointer to that is in the struct vfsmount that we + * have around. + */ + if (!parent) + parent = tracefs_mount->mnt_root; + + mutex_lock(&parent->d_inode->i_mutex); + dentry = lookup_one_len(name, parent, strlen(name)); + if (!IS_ERR(dentry) && dentry->d_inode) { + dput(dentry); + dentry = ERR_PTR(-EEXIST); + } + if (IS_ERR(dentry)) + mutex_unlock(&parent->d_inode->i_mutex); + return dentry; +} + +static struct dentry *failed_creating(struct dentry *dentry) +{ + mutex_unlock(&dentry->d_parent->d_inode->i_mutex); + dput(dentry); + simple_release_fs(&tracefs_mount, &tracefs_mount_count); + return NULL; +} + +static struct dentry *end_creating(struct dentry *dentry) +{ + mutex_unlock(&dentry->d_parent->d_inode->i_mutex); + return dentry; +} + +/** + * tracefs_create_file - create a file in the tracefs filesystem + * @name: a pointer to a string containing the name of the file to create. + * @mode: the permission that the file should have. + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this parameter is NULL, then the + * file will be created in the root of the tracefs filesystem. + * @data: a pointer to something that the caller will want to get to later + * on. The inode.i_private pointer will point to this value on + * the open() call. + * @fops: a pointer to a struct file_operations that should be used for + * this file. + * + * This is the basic "create a file" function for tracefs. It allows for a + * wide range of flexibility in creating a file, or a directory (if you want + * to create a directory, the tracefs_create_dir() function is + * recommended to be used instead.) + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the tracefs_remove() function when the file is + * to be removed (no automatic cleanup happens if your module is unloaded, + * you are responsible here.) If an error occurs, %NULL will be returned. + * + * If tracefs is not enabled in the kernel, the value -%ENODEV will be + * returned. + */ +struct dentry *tracefs_create_file(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops) +{ + struct dentry *dentry; + struct inode *inode; + + if (!(mode & S_IFMT)) + mode |= S_IFREG; + BUG_ON(!S_ISREG(mode)); + dentry = start_creating(name, parent); + + if (IS_ERR(dentry)) + return NULL; + + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) + return failed_creating(dentry); + + inode->i_mode = mode; + inode->i_fop = fops ? fops : &tracefs_file_operations; + inode->i_private = data; + d_instantiate(dentry, inode); + fsnotify_create(dentry->d_parent->d_inode, dentry); + return end_creating(dentry); +} + +/** + * tracefs_create_dir - create a directory in the tracefs filesystem + * @name: a pointer to a string containing the name of the directory to + * create. + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this parameter is NULL, then the + * directory will be created in the root of the tracefs filesystem. + * + * This function creates a directory in tracefs with the given name. + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the tracefs_remove() function when the file is + * to be removed. If an error occurs, %NULL will be returned. + * + * If tracing is not enabled in the kernel, the value -%ENODEV will be + * returned. + */ +struct dentry *tracefs_create_dir(const char *name, struct dentry *parent) +{ + struct dentry *dentry = start_creating(name, parent); + struct inode *inode; + + if (IS_ERR(dentry)) + return NULL; + + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) + return failed_creating(dentry); + + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + inode->i_op = &simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + d_instantiate(dentry, inode); + inc_nlink(dentry->d_parent->d_inode); + fsnotify_mkdir(dentry->d_parent->d_inode, dentry); + return end_creating(dentry); +} + +static inline int tracefs_positive(struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} + +static int __tracefs_remove(struct dentry *dentry, struct dentry *parent) +{ + int ret = 0; + + if (tracefs_positive(dentry)) { + if (dentry->d_inode) { + dget(dentry); + switch (dentry->d_inode->i_mode & S_IFMT) { + case S_IFDIR: + ret = simple_rmdir(parent->d_inode, dentry); + break; + default: + simple_unlink(parent->d_inode, dentry); + break; + } + if (!ret) + d_delete(dentry); + dput(dentry); + } + } + return ret; +} + +/** + * tracefs_remove - removes a file or directory from the tracefs filesystem + * @dentry: a pointer to a the dentry of the file or directory to be + * removed. + * + * This function removes a file or directory in tracefs that was previously + * created with a call to another tracefs function (like + * tracefs_create_file() or variants thereof.) + */ +void tracefs_remove(struct dentry *dentry) +{ + struct dentry *parent; + int ret; + + if (IS_ERR_OR_NULL(dentry)) + return; + + parent = dentry->d_parent; + if (!parent || !parent->d_inode) + return; + + mutex_lock(&parent->d_inode->i_mutex); + ret = __tracefs_remove(dentry, parent); + mutex_unlock(&parent->d_inode->i_mutex); + if (!ret) + simple_release_fs(&tracefs_mount, &tracefs_mount_count); +} + +/** + * tracefs_remove_recursive - recursively removes a directory + * @dentry: a pointer to a the dentry of the directory to be removed. + * + * This function recursively removes a directory tree in tracefs that + * was previously created with a call to another tracefs function + * (like tracefs_create_file() or variants thereof.) + */ +void tracefs_remove_recursive(struct dentry *dentry) +{ + struct dentry *child, *parent; + + if (IS_ERR_OR_NULL(dentry)) + return; + + parent = dentry->d_parent; + if (!parent || !parent->d_inode) + return; + + parent = dentry; + down: + mutex_lock(&parent->d_inode->i_mutex); + loop: + /* + * The parent->d_subdirs is protected by the d_lock. Outside that + * lock, the child can be unlinked and set to be freed which can + * use the d_u.d_child as the rcu head and corrupt this list. + */ + spin_lock(&parent->d_lock); + list_for_each_entry(child, &parent->d_subdirs, d_child) { + if (!tracefs_positive(child)) + continue; + + /* perhaps simple_empty(child) makes more sense */ + if (!list_empty(&child->d_subdirs)) { + spin_unlock(&parent->d_lock); + mutex_unlock(&parent->d_inode->i_mutex); + parent = child; + goto down; + } + + spin_unlock(&parent->d_lock); + + if (!__tracefs_remove(child, parent)) + simple_release_fs(&tracefs_mount, &tracefs_mount_count); + + /* + * The parent->d_lock protects agaist child from unlinking + * from d_subdirs. When releasing the parent->d_lock we can + * no longer trust that the next pointer is valid. + * Restart the loop. We'll skip this one with the + * tracefs_positive() check. + */ + goto loop; + } + spin_unlock(&parent->d_lock); + + mutex_unlock(&parent->d_inode->i_mutex); + child = parent; + parent = parent->d_parent; + mutex_lock(&parent->d_inode->i_mutex); + + if (child != dentry) + /* go up */ + goto loop; + + if (!__tracefs_remove(child, parent)) + simple_release_fs(&tracefs_mount, &tracefs_mount_count); + mutex_unlock(&parent->d_inode->i_mutex); +} + +/** + * tracefs_initialized - Tells whether tracefs has been registered + */ +bool tracefs_initialized(void) +{ + return tracefs_registered; +} + +static int __init tracefs_init(void) +{ + int retval; + + retval = register_filesystem(&trace_fs_type); + if (!retval) + tracefs_registered = true; + + return retval; +} +core_initcall(tracefs_init); diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h new file mode 100644 index 000000000000..23e04ce21749 --- /dev/null +++ b/include/linux/tracefs.h @@ -0,0 +1,41 @@ +/* + * tracefs.h - a pseudo file system for activating tracing + * + * Based on debugfs by: 2004 Greg Kroah-Hartman + * + * Copyright (C) 2014 Red Hat Inc, author: Steven Rostedt + * + * 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. + * + * tracefs is the file system that is used by the tracing infrastructure. + * + */ + +#ifndef _TRACEFS_H_ +#define _TRACEFS_H_ + +#include +#include + +#include + +struct file_operations; + +#ifdef CONFIG_TRACING + +struct dentry *tracefs_create_file(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops); + +struct dentry *tracefs_create_dir(const char *name, struct dentry *parent); + +void tracefs_remove(struct dentry *dentry); +void tracefs_remove_recursive(struct dentry *dentry); + +bool tracefs_initialized(void); + +#endif /* CONFIG_TRACING */ + +#endif diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 7d664ea85ebd..7b1425a6b370 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -58,6 +58,8 @@ #define STACK_END_MAGIC 0x57AC6E9D +#define TRACEFS_MAGIC 0x74726163 + #define V9FS_MAGIC 0x01021997 #define BDEVFS_MAGIC 0x62646576 -- cgit v1.2.3 From eae473581cf93dad94ca833aa961c033c6a43924 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 21 Jan 2015 10:01:39 -0500 Subject: tracing: Have mkdir and rmdir be part of tracefs The tracing "instances" directory can create sub tracing buffers with mkdir, and remove them with rmdir. As a mkdir will also create all the files and directories that control the sub buffer the inode mutexes need to be released before this is done, to avoid deadlocks. It is better to let the tracing system unlock the inode mutexes before calling the functions that create the files within the new directory (or deletes the files from the one being destroyed). Now that tracing has been converted over to tracefs, the tracefs file system can be modified to accommodate this feature. It still releases the locks, but the filesystem itself can take care of the ugly business and let the user just do what it needs. The tracing system now attaches a descriptor to the directory dentry that can have userspace create or remove sub directories. If this descriptor does not exist for a dentry, then that dentry can not be used to create other directories. This descriptor holds a mkdir and rmdir method that only takes a character string as an argument. The tracefs file system will first make a copy of the dentry name before releasing the locks. Then it will pass the copied name to the methods. It is up to the tracing system that supplied the methods to handle races with duplicate names and such as all the inode mutexes would be released when the functions are called. Cc: Al Viro Signed-off-by: Steven Rostedt --- fs/tracefs/inode.c | 151 +++++++++++++++++++++++++++++++++++++++++++----- include/linux/tracefs.h | 4 ++ kernel/trace/trace.c | 75 ++---------------------- 3 files changed, 145 insertions(+), 85 deletions(-) (limited to 'include') diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 0b9cf5cf24c9..d92bdf3b079a 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -50,6 +50,84 @@ static const struct file_operations tracefs_file_operations = { .llseek = noop_llseek, }; +static struct tracefs_dir_ops { + int (*mkdir)(const char *name); + int (*rmdir)(const char *name); +} tracefs_ops; + +static char *get_dname(struct dentry *dentry) +{ + const char *dname; + char *name; + int len = dentry->d_name.len; + + dname = dentry->d_name.name; + name = kmalloc(len + 1, GFP_KERNEL); + if (!name) + return NULL; + memcpy(name, dname, len); + name[len] = 0; + return name; +} + +static int tracefs_syscall_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode) +{ + char *name; + int ret; + + name = get_dname(dentry); + if (!name) + return -ENOMEM; + + /* + * The mkdir call can call the generic functions that create + * the files within the tracefs system. It is up to the individual + * mkdir routine to handle races. + */ + mutex_unlock(&inode->i_mutex); + ret = tracefs_ops.mkdir(name); + mutex_lock(&inode->i_mutex); + + kfree(name); + + return ret; +} + +static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) +{ + char *name; + int ret; + + name = get_dname(dentry); + if (!name) + return -ENOMEM; + + /* + * The rmdir call can call the generic functions that create + * the files within the tracefs system. It is up to the individual + * rmdir routine to handle races. + * This time we need to unlock not only the parent (inode) but + * also the directory that is being deleted. + */ + mutex_unlock(&inode->i_mutex); + mutex_unlock(&dentry->d_inode->i_mutex); + + ret = tracefs_ops.rmdir(name); + + mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); + mutex_lock(&dentry->d_inode->i_mutex); + + kfree(name); + + return ret; +} + +static const struct inode_operations tracefs_dir_inode_operations = { + .lookup = simple_lookup, + .mkdir = tracefs_syscall_mkdir, + .rmdir = tracefs_syscall_rmdir, +}; + static struct inode *tracefs_get_inode(struct super_block *sb) { struct inode *inode = new_inode(sb); @@ -334,6 +412,31 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, return end_creating(dentry); } +static struct dentry *__create_dir(const char *name, struct dentry *parent, + const struct inode_operations *ops) +{ + struct dentry *dentry = start_creating(name, parent); + struct inode *inode; + + if (IS_ERR(dentry)) + return NULL; + + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) + return failed_creating(dentry); + + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + inode->i_op = ops; + inode->i_fop = &simple_dir_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + d_instantiate(dentry, inode); + inc_nlink(dentry->d_parent->d_inode); + fsnotify_mkdir(dentry->d_parent->d_inode, dentry); + return end_creating(dentry); +} + /** * tracefs_create_dir - create a directory in the tracefs filesystem * @name: a pointer to a string containing the name of the directory to @@ -353,26 +456,44 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, */ struct dentry *tracefs_create_dir(const char *name, struct dentry *parent) { - struct dentry *dentry = start_creating(name, parent); - struct inode *inode; + return __create_dir(name, parent, &simple_dir_inode_operations); +} - if (IS_ERR(dentry)) +/** + * tracefs_create_instance_dir - create the tracing instances directory + * @name: The name of the instances directory to create + * @parent: The parent directory that the instances directory will exist + * @mkdir: The function to call when a mkdir is performed. + * @rmdir: The function to call when a rmdir is performed. + * + * Only one instances directory is allowed. + * + * The instances directory is special as it allows for mkdir and rmdir to + * to be done by userspace. When a mkdir or rmdir is performed, the inode + * locks are released and the methhods passed in (@mkdir and @rmdir) are + * called without locks and with the name of the directory being created + * within the instances directory. + * + * Returns the dentry of the instances directory. + */ +struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *parent, + int (*mkdir)(const char *name), + int (*rmdir)(const char *name)) +{ + struct dentry *dentry; + + /* Only allow one instance of the instances directory. */ + if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir)) return NULL; - inode = tracefs_get_inode(dentry->d_sb); - if (unlikely(!inode)) - return failed_creating(dentry); + dentry = __create_dir(name, parent, &tracefs_dir_inode_operations); + if (!dentry) + return NULL; - inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; + tracefs_ops.mkdir = mkdir; + tracefs_ops.rmdir = rmdir; - /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inc_nlink(inode); - d_instantiate(dentry, inode); - inc_nlink(dentry->d_parent->d_inode); - fsnotify_mkdir(dentry->d_parent->d_inode, dentry); - return end_creating(dentry); + return dentry; } static inline int tracefs_positive(struct dentry *dentry) diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h index 23e04ce21749..5b727a17beee 100644 --- a/include/linux/tracefs.h +++ b/include/linux/tracefs.h @@ -34,6 +34,10 @@ struct dentry *tracefs_create_dir(const char *name, struct dentry *parent); void tracefs_remove(struct dentry *dentry); void tracefs_remove_recursive(struct dentry *dentry); +struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *parent, + int (*mkdir)(const char *name), + int (*rmdir)(const char *name)); + bool tracefs_initialized(void); #endif /* CONFIG_TRACING */ diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index b4aa936509d2..3c8913bac204 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6292,7 +6292,7 @@ static void free_trace_buffers(struct trace_array *tr) #endif } -static int new_instance_create(const char *name) +static int instance_mkdir(const char *name) { struct trace_array *tr; int ret; @@ -6362,7 +6362,7 @@ static int new_instance_create(const char *name) } -static int instance_delete(const char *name) +static int instance_rmdir(const char *name) { struct trace_array *tr; int found = 0; @@ -6403,78 +6403,13 @@ static int instance_delete(const char *name) return ret; } -static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode) -{ - struct dentry *parent; - int ret; - - /* Paranoid: Make sure the parent is the "instances" directory */ - parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); - if (WARN_ON_ONCE(parent != trace_instance_dir)) - return -ENOENT; - - /* - * The inode mutex is locked, but tracefs_create_dir() will also - * take the mutex. As the instances directory can not be destroyed - * or changed in any other way, it is safe to unlock it, and - * let the dentry try. If two users try to make the same dir at - * the same time, then the new_instance_create() will determine the - * winner. - */ - mutex_unlock(&inode->i_mutex); - - ret = new_instance_create(dentry->d_iname); - - mutex_lock(&inode->i_mutex); - - return ret; -} - -static int instance_rmdir(struct inode *inode, struct dentry *dentry) -{ - struct dentry *parent; - int ret; - - /* Paranoid: Make sure the parent is the "instances" directory */ - parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); - if (WARN_ON_ONCE(parent != trace_instance_dir)) - return -ENOENT; - - /* The caller did a dget() on dentry */ - mutex_unlock(&dentry->d_inode->i_mutex); - - /* - * The inode mutex is locked, but tracefs_create_dir() will also - * take the mutex. As the instances directory can not be destroyed - * or changed in any other way, it is safe to unlock it, and - * let the dentry try. If two users try to make the same dir at - * the same time, then the instance_delete() will determine the - * winner. - */ - mutex_unlock(&inode->i_mutex); - - ret = instance_delete(dentry->d_iname); - - mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); - mutex_lock(&dentry->d_inode->i_mutex); - - return ret; -} - -static const struct inode_operations instance_dir_inode_operations = { - .lookup = simple_lookup, - .mkdir = instance_mkdir, - .rmdir = instance_rmdir, -}; - static __init void create_trace_instances(struct dentry *d_tracer) { - trace_instance_dir = tracefs_create_dir("instances", d_tracer); + trace_instance_dir = tracefs_create_instance_dir("instances", d_tracer, + instance_mkdir, + instance_rmdir); if (WARN_ON(!trace_instance_dir)) return; - - /* Hijack the dir inode operations, to allow mkdir */ - trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations; } static void -- cgit v1.2.3 From 96bd6224f07b8bf73e0359f15a3d7678118494e6 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:56 +0900 Subject: clk: samsung: exynos5433: Add clocks using common clock framework This patch adds support for the CMU (Clock Management Units) of Exynos5433 which is an Octa-core 64bit SoC. This patch supports necessary clocks (PLL/MMC/UART/MCT/I2C/SPI) for kernel boot and includes binding documentation for Exynos5433 clock controller. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae [s.nawrocki@samsung.com: whitespace cleanup in dt-bindings/clock/exynos5433.h] [ added U suffix to first arguments of PLL_35XX_RATE()] Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/Makefile | 1 + drivers/clk/samsung/clk-exynos5433.c | 963 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 199 +++++++ 3 files changed, 1163 insertions(+) create mode 100644 drivers/clk/samsung/clk-exynos5433.c create mode 100644 include/dt-bindings/clock/exynos5433.h (limited to 'include') diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 006c6f294310..17e9af7fe81f 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o +obj-$(CONFIG_ARCH_EXYNOS5433) += clk-exynos5433.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c new file mode 100644 index 000000000000..a4047390bfc2 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Chanwoo Choi + * + * 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. + * + * Common Clock Framework support for Exynos5443 SoC. + */ + +#include +#include +#include +#include + +#include + +#include "clk.h" +#include "clk-pll.h" + +/* + * Register offset definitions for CMU_TOP + */ +#define ISP_PLL_LOCK 0x0000 +#define AUD_PLL_LOCK 0x0004 +#define ISP_PLL_CON0 0x0100 +#define ISP_PLL_CON1 0x0104 +#define ISP_PLL_FREQ_DET 0x0108 +#define AUD_PLL_CON0 0x0110 +#define AUD_PLL_CON1 0x0114 +#define AUD_PLL_CON2 0x0118 +#define AUD_PLL_FREQ_DET 0x011c +#define MUX_SEL_TOP0 0x0200 +#define MUX_SEL_TOP1 0x0204 +#define MUX_SEL_TOP2 0x0208 +#define MUX_SEL_TOP3 0x020c +#define MUX_SEL_TOP4 0x0210 +#define MUX_SEL_TOP_MSCL 0x0220 +#define MUX_SEL_TOP_CAM1 0x0224 +#define MUX_SEL_TOP_DISP 0x0228 +#define MUX_SEL_TOP_FSYS0 0x0230 +#define MUX_SEL_TOP_FSYS1 0x0234 +#define MUX_SEL_TOP_PERIC0 0x0238 +#define MUX_SEL_TOP_PERIC1 0x023c +#define MUX_ENABLE_TOP0 0x0300 +#define MUX_ENABLE_TOP1 0x0304 +#define MUX_ENABLE_TOP2 0x0308 +#define MUX_ENABLE_TOP3 0x030c +#define MUX_ENABLE_TOP4 0x0310 +#define MUX_ENABLE_TOP_MSCL 0x0320 +#define MUX_ENABLE_TOP_CAM1 0x0324 +#define MUX_ENABLE_TOP_DISP 0x0328 +#define MUX_ENABLE_TOP_FSYS0 0x0330 +#define MUX_ENABLE_TOP_FSYS1 0x0334 +#define MUX_ENABLE_TOP_PERIC0 0x0338 +#define MUX_ENABLE_TOP_PERIC1 0x033c +#define MUX_STAT_TOP0 0x0400 +#define MUX_STAT_TOP1 0x0404 +#define MUX_STAT_TOP2 0x0408 +#define MUX_STAT_TOP3 0x040c +#define MUX_STAT_TOP4 0x0410 +#define MUX_STAT_TOP_MSCL 0x0420 +#define MUX_STAT_TOP_CAM1 0x0424 +#define MUX_STAT_TOP_FSYS0 0x0430 +#define MUX_STAT_TOP_FSYS1 0x0434 +#define MUX_STAT_TOP_PERIC0 0x0438 +#define MUX_STAT_TOP_PERIC1 0x043c +#define DIV_TOP0 0x0600 +#define DIV_TOP1 0x0604 +#define DIV_TOP2 0x0608 +#define DIV_TOP3 0x060c +#define DIV_TOP4 0x0610 +#define DIV_TOP_MSCL 0x0618 +#define DIV_TOP_CAM10 0x061c +#define DIV_TOP_CAM11 0x0620 +#define DIV_TOP_FSYS0 0x062c +#define DIV_TOP_FSYS1 0x0630 +#define DIV_TOP_FSYS2 0x0634 +#define DIV_TOP_PERIC0 0x0638 +#define DIV_TOP_PERIC1 0x063c +#define DIV_TOP_PERIC2 0x0640 +#define DIV_TOP_PERIC3 0x0644 +#define DIV_TOP_PERIC4 0x0648 +#define DIV_TOP_PLL_FREQ_DET 0x064c +#define DIV_STAT_TOP0 0x0700 +#define DIV_STAT_TOP1 0x0704 +#define DIV_STAT_TOP2 0x0708 +#define DIV_STAT_TOP3 0x070c +#define DIV_STAT_TOP4 0x0710 +#define DIV_STAT_TOP_MSCL 0x0718 +#define DIV_STAT_TOP_CAM10 0x071c +#define DIV_STAT_TOP_CAM11 0x0720 +#define DIV_STAT_TOP_FSYS0 0x072c +#define DIV_STAT_TOP_FSYS1 0x0730 +#define DIV_STAT_TOP_FSYS2 0x0734 +#define DIV_STAT_TOP_PERIC0 0x0738 +#define DIV_STAT_TOP_PERIC1 0x073c +#define DIV_STAT_TOP_PERIC2 0x0740 +#define DIV_STAT_TOP_PERIC3 0x0744 +#define DIV_STAT_TOP_PLL_FREQ_DET 0x074c +#define ENABLE_ACLK_TOP 0x0800 +#define ENABLE_SCLK_TOP 0x0a00 +#define ENABLE_SCLK_TOP_MSCL 0x0a04 +#define ENABLE_SCLK_TOP_CAM1 0x0a08 +#define ENABLE_SCLK_TOP_DISP 0x0a0c +#define ENABLE_SCLK_TOP_FSYS 0x0a10 +#define ENABLE_SCLK_TOP_PERIC 0x0a14 +#define ENABLE_IP_TOP 0x0b00 +#define ENABLE_CMU_TOP 0x0c00 +#define ENABLE_CMU_TOP_DIV_STAT 0x0c04 + +static unsigned long top_clk_regs[] __initdata = { + ISP_PLL_LOCK, + AUD_PLL_LOCK, + ISP_PLL_CON0, + ISP_PLL_CON1, + ISP_PLL_FREQ_DET, + AUD_PLL_CON0, + AUD_PLL_CON1, + AUD_PLL_CON2, + AUD_PLL_FREQ_DET, + MUX_SEL_TOP0, + MUX_SEL_TOP1, + MUX_SEL_TOP2, + MUX_SEL_TOP3, + MUX_SEL_TOP4, + MUX_SEL_TOP_MSCL, + MUX_SEL_TOP_CAM1, + MUX_SEL_TOP_DISP, + MUX_SEL_TOP_FSYS0, + MUX_SEL_TOP_FSYS1, + MUX_SEL_TOP_PERIC0, + MUX_SEL_TOP_PERIC1, + MUX_ENABLE_TOP0, + MUX_ENABLE_TOP1, + MUX_ENABLE_TOP2, + MUX_ENABLE_TOP3, + MUX_ENABLE_TOP4, + MUX_ENABLE_TOP_MSCL, + MUX_ENABLE_TOP_CAM1, + MUX_ENABLE_TOP_DISP, + MUX_ENABLE_TOP_FSYS0, + MUX_ENABLE_TOP_FSYS1, + MUX_ENABLE_TOP_PERIC0, + MUX_ENABLE_TOP_PERIC1, + MUX_STAT_TOP0, + MUX_STAT_TOP1, + MUX_STAT_TOP2, + MUX_STAT_TOP3, + MUX_STAT_TOP4, + MUX_STAT_TOP_MSCL, + MUX_STAT_TOP_CAM1, + MUX_STAT_TOP_FSYS0, + MUX_STAT_TOP_FSYS1, + MUX_STAT_TOP_PERIC0, + MUX_STAT_TOP_PERIC1, + DIV_TOP0, + DIV_TOP1, + DIV_TOP2, + DIV_TOP3, + DIV_TOP4, + DIV_TOP_MSCL, + DIV_TOP_CAM10, + DIV_TOP_CAM11, + DIV_TOP_FSYS0, + DIV_TOP_FSYS1, + DIV_TOP_FSYS2, + DIV_TOP_PERIC0, + DIV_TOP_PERIC1, + DIV_TOP_PERIC2, + DIV_TOP_PERIC3, + DIV_TOP_PERIC4, + DIV_TOP_PLL_FREQ_DET, + DIV_STAT_TOP0, + DIV_STAT_TOP1, + DIV_STAT_TOP2, + DIV_STAT_TOP3, + DIV_STAT_TOP4, + DIV_STAT_TOP_MSCL, + DIV_STAT_TOP_CAM10, + DIV_STAT_TOP_CAM11, + DIV_STAT_TOP_FSYS0, + DIV_STAT_TOP_FSYS1, + DIV_STAT_TOP_FSYS2, + DIV_STAT_TOP_PERIC0, + DIV_STAT_TOP_PERIC1, + DIV_STAT_TOP_PERIC2, + DIV_STAT_TOP_PERIC3, + DIV_STAT_TOP_PLL_FREQ_DET, + ENABLE_ACLK_TOP, + ENABLE_SCLK_TOP, + ENABLE_SCLK_TOP_MSCL, + ENABLE_SCLK_TOP_CAM1, + ENABLE_SCLK_TOP_DISP, + ENABLE_SCLK_TOP_FSYS, + ENABLE_SCLK_TOP_PERIC, + ENABLE_IP_TOP, + ENABLE_CMU_TOP, + ENABLE_CMU_TOP_DIV_STAT, +}; + +/* list of all parent clock list */ +PNAME(mout_aud_pll_p) = { "oscclk", "fout_aud_pll", }; +PNAME(mout_isp_pll_p) = { "oscclk", "fout_isp_pll", }; +PNAME(mout_aud_pll_user_p) = { "oscclk", "mout_aud_pll", }; +PNAME(mout_mphy_pll_user_p) = { "oscclk", "sclk_mphy_pll", }; +PNAME(mout_mfc_pll_user_p) = { "oscclk", "sclk_mfc_pll", }; +PNAME(mout_bus_pll_user_p) = { "oscclk", "sclk_bus_pll", }; +PNAME(mout_bus_pll_user_t_p) = { "oscclk", "mout_bus_pll_user", }; + +PNAME(mout_bus_mfc_pll_user_p) = { "mout_bus_pll_user", "mout_mfc_pll_user",}; +PNAME(mout_mfc_bus_pll_user_p) = { "mout_mfc_pll_user", "mout_bus_pll_user",}; +PNAME(mout_aclk_cam1_552_b_p) = { "mout_aclk_cam1_552_a", + "mout_mfc_pll_user", }; +PNAME(mout_aclk_cam1_552_a_p) = { "mout_isp_pll", "mout_bus_pll_user", }; + +PNAME(mout_bus_mphy_pll_user_p) = { "mout_bus_pll_user", + "mout_mphy_pll_user", }; +PNAME(mout_aclk_mscl_b_p) = { "mout_aclk_mscl_400_a", + "mout_mphy_pll_user", }; +PNAME(mout_aclk_g2d_400_b_p) = { "mout_aclk_g2d_400_a", + "mout_mphy_pll_user", }; + +PNAME(mout_sclk_jpeg_c_p) = { "mout_sclk_jpeg_b", "mout_mphy_pll_user",}; +PNAME(mout_sclk_jpeg_b_p) = { "mout_sclk_jpeg_a", "mout_mfc_pll_user", }; + +PNAME(mout_sclk_mmc2_b_p) = { "mout_sclk_mmc2_a", "mout_mfc_pll_user",}; +PNAME(mout_sclk_mmc1_b_p) = { "mout_sclk_mmc1_a", "mout_mfc_pll_user",}; +PNAME(mout_sclk_mmc0_d_p) = { "mout_sclk_mmc0_c", "mout_isp_pll", }; +PNAME(mout_sclk_mmc0_c_p) = { "mout_sclk_mmc0_b", "mout_mphy_pll_user",}; +PNAME(mout_sclk_mmc0_b_p) = { "mout_sclk_mmc0_a", "mout_mfc_pll_user", }; + +static struct samsung_mux_clock top_mux_clks[] __initdata = { + /* MUX_SEL_TOP0 */ + MUX(CLK_MOUT_AUD_PLL, "mout_aud_pll", mout_aud_pll_p, MUX_SEL_TOP0, + 4, 1), + MUX(CLK_MOUT_ISP_PLL, "mout_isp_pll", mout_isp_pll_p, MUX_SEL_TOP0, + 0, 1), + + /* MUX_SEL_TOP1 */ + MUX(CLK_MOUT_AUD_PLL_USER_T, "mout_aud_pll_user_t", + mout_aud_pll_user_p, MUX_SEL_TOP1, 12, 1), + MUX(CLK_MOUT_MPHY_PLL_USER, "mout_mphy_pll_user", mout_mphy_pll_user_p, + MUX_SEL_TOP1, 8, 1), + MUX(CLK_MOUT_MFC_PLL_USER, "mout_mfc_pll_user", mout_mfc_pll_user_p, + MUX_SEL_TOP1, 4, 1), + MUX(CLK_MOUT_BUS_PLL_USER, "mout_bus_pll_user", mout_bus_pll_user_p, + MUX_SEL_TOP1, 0, 1), + + /* MUX_SEL_TOP2 */ + MUX(CLK_MOUT_ACLK_HEVC_400, "mout_aclk_hevc_400", + mout_bus_mfc_pll_user_p, MUX_SEL_TOP2, 28, 1), + MUX(CLK_MOUT_ACLK_CAM1_333, "mout_aclk_cam1_333", + mout_mfc_bus_pll_user_p, MUX_SEL_TOP2, 16, 1), + MUX(CLK_MOUT_ACLK_CAM1_552_B, "mout_aclk_cam1_552_b", + mout_aclk_cam1_552_b_p, MUX_SEL_TOP2, 12, 1), + MUX(CLK_MOUT_ACLK_CAM1_552_A, "mout_aclk_cam1_552_a", + mout_aclk_cam1_552_a_p, MUX_SEL_TOP2, 8, 1), + MUX(CLK_MOUT_ACLK_ISP_DIS_400, "mout_aclk_isp_dis_400", + mout_bus_mfc_pll_user_p, MUX_SEL_TOP2, 4, 1), + MUX(CLK_MOUT_ACLK_ISP_400, "mout_aclk_isp_400", + mout_bus_mfc_pll_user_p, MUX_SEL_TOP2, 0, 1), + + /* MUX_SEL_TOP3 */ + MUX(CLK_MOUT_ACLK_BUS0_400, "mout_aclk_bus0_400", + mout_bus_mphy_pll_user_p, MUX_SEL_TOP3, 20, 1), + MUX(CLK_MOUT_ACLK_MSCL_400_B, "mout_aclk_mscl_400_b", + mout_aclk_mscl_b_p, MUX_SEL_TOP3, 16, 1), + MUX(CLK_MOUT_ACLK_MSCL_400_A, "mout_aclk_mscl_400_a", + mout_bus_mfc_pll_user_p, MUX_SEL_TOP3, 12, 1), + MUX(CLK_MOUT_ACLK_GSCL_333, "mout_aclk_gscl_333", + mout_mfc_bus_pll_user_p, MUX_SEL_TOP3, 8, 1), + MUX(CLK_MOUT_ACLK_G2D_400_B, "mout_aclk_g2d_400_b", + mout_aclk_g2d_400_b_p, MUX_SEL_TOP3, 4, 1), + MUX(CLK_MOUT_ACLK_G2D_400_A, "mout_aclk_g2d_400_a", + mout_bus_mfc_pll_user_p, MUX_SEL_TOP3, 0, 1), + + /* MUX_SEL_TOP_MSCL */ + MUX(CLK_MOUT_SCLK_JPEG_C, "mout_sclk_jpeg_c", mout_sclk_jpeg_c_p, + MUX_SEL_TOP_MSCL, 8, 1), + MUX(CLK_MOUT_SCLK_JPEG_B, "mout_sclk_jpeg_b", mout_sclk_jpeg_b_p, + MUX_SEL_TOP_MSCL, 4, 1), + MUX(CLK_MOUT_SCLK_JPEG_A, "mout_sclk_jpeg_a", mout_bus_pll_user_t_p, + MUX_SEL_TOP_MSCL, 0, 1), + + /* MUX_SEL_TOP_FSYS0 */ + MUX(CLK_MOUT_SCLK_MMC2_B, "mout_sclk_mmc2_b", mout_sclk_mmc2_b_p, + MUX_SEL_TOP_FSYS0, 28, 1), + MUX(CLK_MOUT_SCLK_MMC2_A, "mout_sclk_mmc2_a", mout_bus_pll_user_t_p, + MUX_SEL_TOP_FSYS0, 24, 1), + MUX(CLK_MOUT_SCLK_MMC1_B, "mout_sclk_mmc1_b", mout_sclk_mmc1_b_p, + MUX_SEL_TOP_FSYS0, 20, 1), + MUX(CLK_MOUT_SCLK_MMC1_A, "mout_sclk_mmc1_a", mout_bus_pll_user_t_p, + MUX_SEL_TOP_FSYS0, 16, 1), + MUX(CLK_MOUT_SCLK_MMC0_D, "mout_sclk_mmc0_d", mout_sclk_mmc0_d_p, + MUX_SEL_TOP_FSYS0, 12, 1), + MUX(CLK_MOUT_SCLK_MMC0_C, "mout_sclk_mmc0_c", mout_sclk_mmc0_c_p, + MUX_SEL_TOP_FSYS0, 8, 1), + MUX(CLK_MOUT_SCLK_MMC0_B, "mout_sclk_mmc0_b", mout_sclk_mmc0_b_p, + MUX_SEL_TOP_FSYS0, 4, 1), + MUX(CLK_MOUT_SCLK_MMC0_A, "mout_sclk_mmc0_a", mout_bus_pll_user_t_p, + MUX_SEL_TOP_FSYS0, 0, 1), + + /* MUX_SEL_TOP_PERIC0 */ + MUX(CLK_MOUT_SCLK_SPI4, "mout_sclk_spi4", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 28, 1), + MUX(CLK_MOUT_SCLK_SPI3, "mout_sclk_spi3", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 24, 1), + MUX(CLK_MOUT_SCLK_UART2, "mout_sclk_uart2", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 20, 1), + MUX(CLK_MOUT_SCLK_UART1, "mout_sclk_uart1", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 16, 1), + MUX(CLK_MOUT_SCLK_UART0, "mout_sclk_uart0", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 12, 1), + MUX(CLK_MOUT_SCLK_SPI2, "mout_sclk_spi2", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 8, 1), + MUX(CLK_MOUT_SCLK_SPI1, "mout_sclk_spi1", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 4, 1), + MUX(CLK_MOUT_SCLK_SPI0, "mout_sclk_spi0", mout_bus_pll_user_t_p, + MUX_SEL_TOP_PERIC0, 0, 1), +}; + +static struct samsung_div_clock top_div_clks[] __initdata = { + /* DIV_TOP2 */ + DIV(CLK_DIV_ACLK_FSYS_200, "div_aclk_fsys_200", "mout_bus_pll_user", + DIV_TOP2, 0, 3), + + /* DIV_TOP3 */ + DIV(CLK_DIV_ACLK_IMEM_SSSX_266, "div_aclk_imem_sssx_266", + "mout_bus_pll_user", DIV_TOP3, 24, 3), + DIV(CLK_DIV_ACLK_IMEM_200, "div_aclk_imem_200", + "mout_bus_pll_user", DIV_TOP3, 20, 3), + DIV(CLK_DIV_ACLK_IMEM_266, "div_aclk_imem_266", + "mout_bus_pll_user", DIV_TOP3, 16, 3), + DIV(CLK_DIV_ACLK_PERIC_66_B, "div_aclk_peric_66_b", + "div_aclk_peric_66_a", DIV_TOP3, 12, 3), + DIV(CLK_DIV_ACLK_PERIC_66_A, "div_aclk_peric_66_a", + "mout_bus_pll_user", DIV_TOP3, 8, 3), + DIV(CLK_DIV_ACLK_PERIS_66_B, "div_aclk_peris_66_b", + "div_aclk_peris_66_a", DIV_TOP3, 4, 3), + DIV(CLK_DIV_ACLK_PERIS_66_A, "div_aclk_peris_66_a", + "mout_bus_pll_user", DIV_TOP3, 0, 3), + + /* DIV_TOP_FSYS0 */ + DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", + DIV_TOP_FSYS0, 16, 8), + DIV(CLK_DIV_SCLK_MMC1_A, "div_sclk_mmc1_a", "mout_sclk_mmc1_b", + DIV_TOP_FSYS0, 12, 4), + DIV_F(CLK_DIV_SCLK_MMC0_B, "div_sclk_mmc0_b", "div_sclk_mmc0_a", + DIV_TOP_FSYS0, 4, 8, CLK_SET_RATE_PARENT, 0), + DIV_F(CLK_DIV_SCLK_MMC0_A, "div_sclk_mmc0_a", "mout_sclk_mmc0_d", + DIV_TOP_FSYS0, 0, 4, CLK_SET_RATE_PARENT, 0), + + /* DIV_TOP_FSYS1 */ + DIV(CLK_DIV_SCLK_MMC2_B, "div_sclk_mmc2_b", "div_sclk_mmc2_a", + DIV_TOP_FSYS1, 4, 8), + DIV(CLK_DIV_SCLK_MMC2_A, "div_sclk_mmc2_a", "mout_sclk_mmc2_b", + DIV_TOP_FSYS1, 0, 4), + + /* DIV_TOP_PERIC0 */ + DIV(CLK_DIV_SCLK_SPI1_B, "div_sclk_spi1_b", "div_sclk_spi1_a", + DIV_TOP_PERIC0, 16, 8), + DIV(CLK_DIV_SCLK_SPI1_A, "div_sclk_spi1_a", "mout_sclk_spi1", + DIV_TOP_PERIC0, 12, 4), + DIV(CLK_DIV_SCLK_SPI0_B, "div_sclk_spi0_b", "div_sclk_spi0_a", + DIV_TOP_PERIC0, 4, 8), + DIV(CLK_DIV_SCLK_SPI0_A, "div_sclk_spi0_a", "mout_sclk_spi0", + DIV_TOP_PERIC0, 0, 4), + + /* DIV_TOP_PERIC1 */ + DIV(CLK_DIV_SCLK_SPI2_B, "div_sclk_spi2_b", "div_sclk_spi2_a", + DIV_TOP_PERIC1, 4, 8), + DIV(CLK_DIV_SCLK_SPI2_A, "div_sclk_spi2_a", "mout_sclk_spi2", + DIV_TOP_PERIC1, 0, 4), + + /* DIV_TOP_PERIC2 */ + DIV(CLK_DIV_SCLK_UART2, "div_sclk_uart2", "mout_sclk_uart2", + DIV_TOP_PERIC2, 8, 4), + DIV(CLK_DIV_SCLK_UART1, "div_sclk_uart1", "mout_sclk_uart0", + DIV_TOP_PERIC2, 4, 4), + DIV(CLK_DIV_SCLK_UART0, "div_sclk_uart0", "mout_sclk_uart1", + DIV_TOP_PERIC2, 0, 4), + + /* DIV_TOP_PERIC4 */ + DIV(CLK_DIV_SCLK_SPI4_B, "div_sclk_spi4_b", "div_sclk_spi4_a", + DIV_TOP_PERIC4, 16, 8), + DIV(CLK_DIV_SCLK_SPI4_A, "div_sclk_spi4_a", "mout_sclk_spi4", + DIV_TOP_PERIC4, 12, 4), + DIV(CLK_DIV_SCLK_SPI3_B, "div_sclk_spi3_b", "div_sclk_spi3_a", + DIV_TOP_PERIC4, 4, 8), + DIV(CLK_DIV_SCLK_SPI3_A, "div_sclk_spi3_a", "mout_sclk_spi3", + DIV_TOP_PERIC4, 0, 4), +}; + +static struct samsung_gate_clock top_gate_clks[] __initdata = { + /* ENABLE_ACLK_TOP */ + GATE(CLK_ACLK_PERIC_66, "aclk_peric_66", "div_aclk_peric_66_b", + ENABLE_ACLK_TOP, 22, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PERIS_66, "aclk_peris_66", "div_aclk_peris_66_b", + ENABLE_ACLK_TOP, 21, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_FSYS_200, "aclk_fsys_200", "div_aclk_fsys_200", + ENABLE_ACLK_TOP, 18, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_TOP_FSYS */ + GATE(CLK_SCLK_MMC2_FSYS, "sclk_mmc2_fsys", "div_sclk_mmc2_b", + ENABLE_SCLK_TOP_FSYS, 6, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_MMC1_FSYS, "sclk_mmc1_fsys", "div_sclk_mmc1_b", + ENABLE_SCLK_TOP_FSYS, 5, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_MMC0_FSYS, "sclk_mmc0_fsys", "div_sclk_mmc0_b", + ENABLE_SCLK_TOP_FSYS, 4, CLK_SET_RATE_PARENT, 0), + + /* ENABLE_SCLK_TOP_PERIC */ + GATE(CLK_SCLK_SPI4_PERIC, "sclk_spi4_peric", "div_sclk_spi4_b", + ENABLE_SCLK_TOP_PERIC, 12, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPI3_PERIC, "sclk_spi3_peric", "div_sclk_spi3_b", + ENABLE_SCLK_TOP_PERIC, 11, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UART2_PERIC, "sclk_uart2_peric", "div_sclk_uart2", + ENABLE_SCLK_TOP_PERIC, 5, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UART1_PERIC, "sclk_uart1_peric", "div_sclk_uart1", + ENABLE_SCLK_TOP_PERIC, 4, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UART0_PERIC, "sclk_uart0_peric", "div_sclk_uart0", + ENABLE_SCLK_TOP_PERIC, 3, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPI2_PERIC, "sclk_spi2_peric", "div_sclk_spi2_b", + ENABLE_SCLK_TOP_PERIC, 2, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPI1_PERIC, "sclk_spi1_peric", "div_sclk_spi1_b", + ENABLE_SCLK_TOP_PERIC, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPI0_PERIC, "sclk_spi0_peric", "div_sclk_spi0_b", + ENABLE_SCLK_TOP_PERIC, 0, CLK_SET_RATE_PARENT, 0), +}; + +/* + * ATLAS_PLL & APOLLO_PLL & MEM0_PLL & MEM1_PLL & BUS_PLL & MFC_PLL + * & MPHY_PLL & G3D_PLL & DISP_PLL & ISP_PLL + */ +static struct samsung_pll_rate_table exynos5443_pll_rates[] = { + PLL_35XX_RATE(2500000000U, 625, 6, 0), + PLL_35XX_RATE(2400000000U, 500, 5, 0), + PLL_35XX_RATE(2300000000U, 575, 6, 0), + PLL_35XX_RATE(2200000000U, 550, 6, 0), + PLL_35XX_RATE(2100000000U, 350, 4, 0), + PLL_35XX_RATE(2000000000U, 500, 6, 0), + PLL_35XX_RATE(1900000000U, 475, 6, 0), + PLL_35XX_RATE(1800000000U, 375, 5, 0), + PLL_35XX_RATE(1700000000U, 425, 6, 0), + PLL_35XX_RATE(1600000000U, 400, 6, 0), + PLL_35XX_RATE(1500000000U, 250, 4, 0), + PLL_35XX_RATE(1400000000U, 350, 6, 0), + PLL_35XX_RATE(1332000000U, 222, 4, 0), + PLL_35XX_RATE(1300000000U, 325, 6, 0), + PLL_35XX_RATE(1200000000U, 500, 5, 1), + PLL_35XX_RATE(1100000000U, 550, 6, 1), + PLL_35XX_RATE(1086000000U, 362, 4, 1), + PLL_35XX_RATE(1066000000U, 533, 6, 1), + PLL_35XX_RATE(1000000000U, 500, 6, 1), + PLL_35XX_RATE(933000000U, 311, 4, 1), + PLL_35XX_RATE(921000000U, 307, 4, 1), + PLL_35XX_RATE(900000000U, 375, 5, 1), + PLL_35XX_RATE(825000000U, 275, 4, 1), + PLL_35XX_RATE(800000000U, 400, 6, 1), + PLL_35XX_RATE(733000000U, 733, 12, 1), + PLL_35XX_RATE(700000000U, 360, 6, 1), + PLL_35XX_RATE(667000000U, 222, 4, 1), + PLL_35XX_RATE(633000000U, 211, 4, 1), + PLL_35XX_RATE(600000000U, 500, 5, 2), + PLL_35XX_RATE(552000000U, 460, 5, 2), + PLL_35XX_RATE(550000000U, 550, 6, 2), + PLL_35XX_RATE(543000000U, 362, 4, 2), + PLL_35XX_RATE(533000000U, 533, 6, 2), + PLL_35XX_RATE(500000000U, 500, 6, 2), + PLL_35XX_RATE(444000000U, 370, 5, 2), + PLL_35XX_RATE(420000000U, 350, 5, 2), + PLL_35XX_RATE(400000000U, 400, 6, 2), + PLL_35XX_RATE(350000000U, 360, 6, 2), + PLL_35XX_RATE(333000000U, 222, 4, 2), + PLL_35XX_RATE(300000000U, 500, 5, 3), + PLL_35XX_RATE(266000000U, 532, 6, 3), + PLL_35XX_RATE(200000000U, 400, 6, 3), + PLL_35XX_RATE(166000000U, 332, 6, 3), + PLL_35XX_RATE(160000000U, 320, 6, 3), + PLL_35XX_RATE(133000000U, 552, 6, 4), + PLL_35XX_RATE(100000000U, 400, 6, 4), + { /* sentinel */ } +}; + +/* AUD_PLL */ +static struct samsung_pll_rate_table exynos5443_aud_pll_rates[] = { + PLL_36XX_RATE(400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(393216000U, 197, 3, 2, -25690), + PLL_36XX_RATE(384000000U, 128, 2, 2, 0), + PLL_36XX_RATE(368640000U, 246, 4, 2, -15729), + PLL_36XX_RATE(361507200U, 181, 3, 2, -16148), + PLL_36XX_RATE(338688000U, 113, 2, 2, -6816), + PLL_36XX_RATE(294912000U, 98, 1, 3, 19923), + PLL_36XX_RATE(288000000U, 96, 1, 3, 0), + PLL_36XX_RATE(252000000U, 84, 1, 3, 0), + { /* sentinel */ } +}; + +static struct samsung_pll_clock top_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "oscclk", + ISP_PLL_LOCK, ISP_PLL_CON0, exynos5443_pll_rates), + PLL(pll_36xx, CLK_FOUT_AUD_PLL, "fout_aud_pll", "oscclk", + AUD_PLL_LOCK, AUD_PLL_CON0, exynos5443_aud_pll_rates), +}; + +static struct samsung_cmu_info top_cmu_info __initdata = { + .pll_clks = top_pll_clks, + .nr_pll_clks = ARRAY_SIZE(top_pll_clks), + .mux_clks = top_mux_clks, + .nr_mux_clks = ARRAY_SIZE(top_mux_clks), + .div_clks = top_div_clks, + .nr_div_clks = ARRAY_SIZE(top_div_clks), + .gate_clks = top_gate_clks, + .nr_gate_clks = ARRAY_SIZE(top_gate_clks), + .nr_clk_ids = TOP_NR_CLK, + .clk_regs = top_clk_regs, + .nr_clk_regs = ARRAY_SIZE(top_clk_regs), +}; + +static void __init exynos5433_cmu_top_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &top_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_top, "samsung,exynos5433-cmu-top", + exynos5433_cmu_top_init); + +/* + * Register offset definitions for CMU_CPIF + */ +#define MPHY_PLL_LOCK 0x0000 +#define MPHY_PLL_CON0 0x0100 +#define MPHY_PLL_CON1 0x0104 +#define MPHY_PLL_FREQ_DET 0x010c +#define MUX_SEL_CPIF0 0x0200 +#define DIV_CPIF 0x0600 +#define ENABLE_SCLK_CPIF 0x0a00 + +static unsigned long cpif_clk_regs[] __initdata = { + MPHY_PLL_LOCK, + MPHY_PLL_CON0, + MPHY_PLL_CON1, + MPHY_PLL_FREQ_DET, + MUX_SEL_CPIF0, + ENABLE_SCLK_CPIF, +}; + +/* list of all parent clock list */ +PNAME(mout_mphy_pll_p) = { "oscclk", "fout_mphy_pll", }; + +static struct samsung_pll_clock cpif_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_MPHY_PLL, "fout_mphy_pll", "oscclk", + MPHY_PLL_LOCK, MPHY_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_mux_clock cpif_mux_clks[] __initdata = { + /* MUX_SEL_CPIF0 */ + MUX(CLK_MOUT_MPHY_PLL, "mout_mphy_pll", mout_mphy_pll_p, MUX_SEL_CPIF0, + 0, 1), +}; + +static struct samsung_div_clock cpif_div_clks[] __initdata = { + /* DIV_CPIF */ + DIV(CLK_DIV_SCLK_MPHY, "div_sclk_mphy", "mout_mphy_pll", DIV_CPIF, + 0, 6), +}; + +static struct samsung_gate_clock cpif_gate_clks[] __initdata = { + /* ENABLE_SCLK_CPIF */ + GATE(CLK_SCLK_MPHY_PLL, "sclk_mphy_pll", "mout_mphy_pll", + ENABLE_SCLK_CPIF, 9, 0, 0), + GATE(CLK_SCLK_UFS_MPHY, "sclk_ufs_mphy", "div_sclk_mphy", + ENABLE_SCLK_CPIF, 4, 0, 0), +}; + +static struct samsung_cmu_info cpif_cmu_info __initdata = { + .pll_clks = cpif_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cpif_pll_clks), + .mux_clks = cpif_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cpif_mux_clks), + .div_clks = cpif_div_clks, + .nr_div_clks = ARRAY_SIZE(cpif_div_clks), + .gate_clks = cpif_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cpif_gate_clks), + .nr_clk_ids = CPIF_NR_CLK, + .clk_regs = cpif_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cpif_clk_regs), +}; + +static void __init exynos5433_cmu_cpif_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &cpif_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_cpif, "samsung,exynos5433-cmu-cpif", + exynos5433_cmu_cpif_init); + +/* + * Register offset definitions for CMU_MIF + */ +#define MEM0_PLL_LOCK 0x0000 +#define MEM1_PLL_LOCK 0x0004 +#define BUS_PLL_LOCK 0x0008 +#define MFC_PLL_LOCK 0x000c +#define MEM0_PLL_CON0 0x0100 +#define MEM0_PLL_CON1 0x0104 +#define MEM0_PLL_FREQ_DET 0x010c +#define MEM1_PLL_CON0 0x0110 +#define MEM1_PLL_CON1 0x0114 +#define MEM1_PLL_FREQ_DET 0x011c +#define BUS_PLL_CON0 0x0120 +#define BUS_PLL_CON1 0x0124 +#define BUS_PLL_FREQ_DET 0x012c +#define MFC_PLL_CON0 0x0130 +#define MFC_PLL_CON1 0x0134 +#define MFC_PLL_FREQ_DET 0x013c + +static unsigned long mif_clk_regs[] __initdata = { + MEM0_PLL_LOCK, + MEM1_PLL_LOCK, + BUS_PLL_LOCK, + MFC_PLL_LOCK, + MEM0_PLL_CON0, + MEM0_PLL_CON1, + MEM0_PLL_FREQ_DET, + MEM1_PLL_CON0, + MEM1_PLL_CON1, + MEM1_PLL_FREQ_DET, + BUS_PLL_CON0, + BUS_PLL_CON1, + BUS_PLL_FREQ_DET, + MFC_PLL_CON0, + MFC_PLL_CON1, + MFC_PLL_FREQ_DET, +}; + +static struct samsung_pll_clock mif_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_MEM0_PLL, "fout_mem0_pll", "oscclk", + MEM0_PLL_LOCK, MEM0_PLL_CON0, exynos5443_pll_rates), + PLL(pll_35xx, CLK_FOUT_MEM1_PLL, "fout_mem1_pll", "oscclk", + MEM1_PLL_LOCK, MEM1_PLL_CON0, exynos5443_pll_rates), + PLL(pll_35xx, CLK_FOUT_BUS_PLL, "fout_bus_pll", "oscclk", + BUS_PLL_LOCK, BUS_PLL_CON0, exynos5443_pll_rates), + PLL(pll_35xx, CLK_FOUT_MFC_PLL, "fout_mfc_pll", "oscclk", + MFC_PLL_LOCK, MFC_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_cmu_info mif_cmu_info __initdata = { + .pll_clks = mif_pll_clks, + .nr_pll_clks = ARRAY_SIZE(mif_pll_clks), + .nr_clk_ids = MIF_NR_CLK, + .clk_regs = mif_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mif_clk_regs), +}; + +static void __init exynos5433_cmu_mif_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &mif_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_mif, "samsung,exynos5433-cmu-mif", + exynos5433_cmu_mif_init); + +/* + * Register offset definitions for CMU_PERIC + */ +#define DIV_PERIC 0x0600 +#define ENABLE_ACLK_PERIC 0x0800 +#define ENABLE_PCLK_PERIC0 0x0900 +#define ENABLE_PCLK_PERIC1 0x0904 +#define ENABLE_SCLK_PERIC 0x0A00 +#define ENABLE_IP_PERIC0 0x0B00 +#define ENABLE_IP_PERIC1 0x0B04 +#define ENABLE_IP_PERIC2 0x0B08 + +static unsigned long peric_clk_regs[] __initdata = { + DIV_PERIC, + ENABLE_ACLK_PERIC, + ENABLE_PCLK_PERIC0, + ENABLE_PCLK_PERIC1, + ENABLE_SCLK_PERIC, + ENABLE_IP_PERIC0, + ENABLE_IP_PERIC1, + ENABLE_IP_PERIC2, +}; + +static struct samsung_gate_clock peric_gate_clks[] __initdata = { + /* ENABLE_PCLK_PERIC0 */ + GATE(CLK_PCLK_SPI2, "pclk_spi2", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 23, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_SPI1, "pclk_spi1", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 22, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_SPI0, "pclk_spi0", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_UART2, "pclk_uart2", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 14, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_UART1, "pclk_uart1", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 13, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_UART0, "pclk_uart0", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 12, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C3, "pclk_hsi2c3", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 11, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C2, "pclk_hsi2c2", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 10, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C1, "pclk_hsi2c1", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 9, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C0, "pclk_hsi2c0", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 8, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C7, "pclk_i2c7", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 7, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C6, "pclk_i2c6", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 6, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C5, "pclk_i2c5", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 5, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C4, "pclk_i2c4", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 4, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C3, "pclk_i2c3", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 3, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C2, "pclk_i2c2", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 2, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C1, "pclk_i2c1", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2C0, "pclk_i2c0", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 0, CLK_SET_RATE_PARENT, 0), + + /* ENABLE_PCLK_PERIC1 */ + GATE(CLK_PCLK_SPI4, "pclk_spi4", "aclk_peric_66", ENABLE_PCLK_PERIC1, + 9, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_SPI3, "pclk_spi3", "aclk_peric_66", ENABLE_PCLK_PERIC1, + 8, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C11, "pclk_hsi2c11", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 7, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C10, "pclk_hsi2c10", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 6, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C9, "pclk_hsi2c9", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 5, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C8, "pclk_hsi2c8", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 4, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C7, "pclk_hsi2c7", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 3, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C6, "pclk_hsi2c6", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 2, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C5, "pclk_hsi2c5", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_HSI2C4, "pclk_hsi2c4", "aclk_peric_66", + ENABLE_PCLK_PERIC1, 0, CLK_SET_RATE_PARENT, 0), + + /* ENABLE_SCLK_PERIC */ + GATE(CLK_SCLK_SPI4, "sclk_spi4", "sclk_spi4_peric", ENABLE_SCLK_PERIC, + 19, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPI3, "sclk_spi3", "sclk_spi3_peric", ENABLE_SCLK_PERIC, + 18, CLK_SET_RATE_PARENT, 0), + + GATE(CLK_SCLK_SPI2, "sclk_spi2", "sclk_spi2_peric", ENABLE_SCLK_PERIC, + 5, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPI1, "sclk_spi1", "sclk_spi1_peric", ENABLE_SCLK_PERIC, + 4, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPI0, "sclk_spi0", "sclk_spi0_peric", ENABLE_SCLK_PERIC, + 3, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UART2, "sclk_uart2", "sclk_uart2_peric", + ENABLE_SCLK_PERIC, 2, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UART1, "sclk_uart1", "sclk_uart1_peric", + ENABLE_SCLK_PERIC, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UART0, "sclk_uart0", "sclk_uart0_peric", + ENABLE_SCLK_PERIC, 0, CLK_SET_RATE_PARENT, 0), +}; + +static struct samsung_cmu_info peric_cmu_info __initdata = { + .gate_clks = peric_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peric_gate_clks), + .nr_clk_ids = PERIC_NR_CLK, + .clk_regs = peric_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric_clk_regs), +}; + +static void __init exynos5433_cmu_peric_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &peric_cmu_info); +} + +CLK_OF_DECLARE(exynos5433_cmu_peric, "samsung,exynos5433-cmu-peric", + exynos5433_cmu_peric_init); + +/* + * Register offset definitions for CMU_PERIS + */ +#define ENABLE_ACLK_PERIS 0x0800 +#define ENABLE_PCLK_PERIS 0x0900 + +static unsigned long peris_clk_regs[] __initdata = { + ENABLE_ACLK_PERIS, + ENABLE_PCLK_PERIS, +}; + +static struct samsung_gate_clock peris_gate_clks[] __initdata = { + /* ENABLE_PCLK_PERIS */ + GATE(CLK_PCLK_HPM_APBIF, "pclk_hpm_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS, 30, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_TMU1_APBIF, "pclk_tmu1_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_TMU0_APBIF, "pclk_tmu0_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_PERIS, "pclk_pmu_peris", "aclk_peris_66", + ENABLE_PCLK_PERIS, 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_PERIS, "pclk_sysreg_peris", "aclk_peris_66", + ENABLE_PCLK_PERIS, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CMU_TOP_APBIF, "pclk_cmu_top_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_WDT_APOLLO, "pclk_wdt_apollo", "aclk_peris_66", + ENABLE_PCLK_PERIS, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_WDT_ATLAS, "pclk_wdt_atlas", "aclk_peris_66", + ENABLE_PCLK_PERIS, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_MCT, "pclk_mct", "aclk_peris_66", + ENABLE_PCLK_PERIS, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_HDMI_CEC, "pclk_hdmi_cec", "aclk_peris_66", + ENABLE_PCLK_PERIS, 14, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info peris_cmu_info __initdata = { + .gate_clks = peris_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peris_gate_clks), + .nr_clk_ids = PERIS_NR_CLK, + .clk_regs = peris_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peris_clk_regs), +}; + +static void __init exynos5433_cmu_peris_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &peris_cmu_info); +} + +CLK_OF_DECLARE(exynos5433_cmu_peris, "samsung,exynos5433-cmu-peris", + exynos5433_cmu_peris_init); + +/* + * Register offset definitions for CMU_FSYS + */ +#define MUX_SEL_FSYS0 0x0200 +#define MUX_SEL_FSYS1 0x0204 +#define MUX_SEL_FSYS2 0x0208 +#define MUX_SEL_FSYS3 0x020c +#define MUX_SEL_FSYS4 0x0210 +#define MUX_ENABLE_FSYS0 0x0300 +#define MUX_ENABLE_FSYS1 0x0304 +#define MUX_ENABLE_FSYS2 0x0308 +#define MUX_ENABLE_FSYS3 0x030c +#define MUX_ENABLE_FSYS4 0x0310 +#define MUX_STAT_FSYS0 0x0400 +#define MUX_STAT_FSYS1 0x0404 +#define MUX_STAT_FSYS2 0x0408 +#define MUX_STAT_FSYS3 0x040c +#define MUX_STAT_FSYS4 0x0410 +#define MUX_IGNORE_FSYS2 0x0508 +#define MUX_IGNORE_FSYS3 0x050c +#define ENABLE_ACLK_FSYS0 0x0800 +#define ENABLE_ACLK_FSYS1 0x0804 +#define ENABLE_PCLK_FSYS 0x0900 +#define ENABLE_SCLK_FSYS 0x0a00 +#define ENABLE_IP_FSYS0 0x0b00 +#define ENABLE_IP_FSYS1 0x0b04 + +/* list of all parent clock list */ +PNAME(mout_aclk_fsys_200_user_p) = { "oscclk", "div_aclk_fsys_200", }; +PNAME(mout_sclk_mmc2_user_p) = { "oscclk", "sclk_mmc2_fsys", }; +PNAME(mout_sclk_mmc1_user_p) = { "oscclk", "sclk_mmc1_fsys", }; +PNAME(mout_sclk_mmc0_user_p) = { "oscclk", "sclk_mmc0_fsys", }; + +static unsigned long fsys_clk_regs[] __initdata = { + MUX_SEL_FSYS0, + MUX_SEL_FSYS1, + MUX_SEL_FSYS2, + MUX_SEL_FSYS3, + MUX_SEL_FSYS4, + MUX_ENABLE_FSYS0, + MUX_ENABLE_FSYS1, + MUX_ENABLE_FSYS2, + MUX_ENABLE_FSYS3, + MUX_ENABLE_FSYS4, + MUX_STAT_FSYS0, + MUX_STAT_FSYS1, + MUX_STAT_FSYS2, + MUX_STAT_FSYS3, + MUX_STAT_FSYS4, + MUX_IGNORE_FSYS2, + MUX_IGNORE_FSYS3, + ENABLE_ACLK_FSYS0, + ENABLE_ACLK_FSYS1, + ENABLE_PCLK_FSYS, + ENABLE_SCLK_FSYS, + ENABLE_IP_FSYS0, + ENABLE_IP_FSYS1, +}; + +static struct samsung_mux_clock fsys_mux_clks[] __initdata = { + /* MUX_SEL_FSYS0 */ + MUX(CLK_MOUT_ACLK_FSYS_200_USER, "mout_aclk_fsys_200_user", + mout_aclk_fsys_200_user_p, MUX_SEL_FSYS0, 0, 1), + + /* MUX_SEL_FSYS1 */ + MUX(CLK_MOUT_SCLK_MMC2_USER, "mout_sclk_mmc2_user", + mout_sclk_mmc2_user_p, MUX_SEL_FSYS1, 20, 1), + MUX(CLK_MOUT_SCLK_MMC1_USER, "mout_sclk_mmc1_user", + mout_sclk_mmc1_user_p, MUX_SEL_FSYS1, 16, 1), + MUX(CLK_MOUT_SCLK_MMC0_USER, "mout_sclk_mmc0_user", + mout_sclk_mmc0_user_p, MUX_SEL_FSYS1, 12, 1), +}; + +static struct samsung_gate_clock fsys_gate_clks[] __initdata = { + /* ENABLE_ACLK_FSYS0 */ + GATE(CLK_ACLK_PCIE, "aclk_pcie", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PDMA1, "aclk_pdma1", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_TSI, "aclk_tsi", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MMC2, "aclk_mmc2", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MMC1, "aclk_mmc1", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MMC0, "aclk_mmc0", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_UFS, "aclk_ufs", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_USBHOST20, "aclk_usbhost20", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_USBHOST30, "aclk_usbhost30", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_USBDRD30, "aclk_usbdrd30", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS0, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_FSYS */ + GATE(CLK_SCLK_MMC2, "sclk_mmc2", "mout_sclk_mmc2_user", + ENABLE_SCLK_FSYS, 4, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_MMC1, "sclk_mmc1", "mout_sclk_mmc1_user", + ENABLE_SCLK_FSYS, 3, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_MMC0, "sclk_mmc0", "mout_sclk_mmc0_user", + ENABLE_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0), + + /* ENABLE_IP_FSYS0 */ + GATE(CLK_PDMA1, "pdma1", "aclk_pdma1", ENABLE_IP_FSYS0, 15, 0, 0), + GATE(CLK_PDMA0, "pdma0", "aclk_pdma0", ENABLE_IP_FSYS0, 0, 0, 0), +}; + +static struct samsung_cmu_info fsys_cmu_info __initdata = { + .mux_clks = fsys_mux_clks, + .nr_mux_clks = ARRAY_SIZE(fsys_mux_clks), + .gate_clks = fsys_gate_clks, + .nr_gate_clks = ARRAY_SIZE(fsys_gate_clks), + .nr_clk_ids = FSYS_NR_CLK, + .clk_regs = fsys_clk_regs, + .nr_clk_regs = ARRAY_SIZE(fsys_clk_regs), +}; + +static void __init exynos5433_cmu_fsys_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &fsys_cmu_info); +} + +CLK_OF_DECLARE(exynos5433_cmu_fsys, "samsung,exynos5433-cmu-fsys", + exynos5433_cmu_fsys_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h new file mode 100644 index 000000000000..5c4e2e39ce49 --- /dev/null +++ b/include/dt-bindings/clock/exynos5433.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Chanwoo Choi + * + * 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 _DT_BINDINGS_CLOCK_EXYNOS5433_H +#define _DT_BINDINGS_CLOCK_EXYNOS5433_H + +/* CMU_TOP */ +#define CLK_FOUT_ISP_PLL 1 +#define CLK_FOUT_AUD_PLL 2 + +#define CLK_MOUT_AUD_PLL 10 +#define CLK_MOUT_ISP_PLL 11 +#define CLK_MOUT_AUD_PLL_USER_T 12 +#define CLK_MOUT_MPHY_PLL_USER 13 +#define CLK_MOUT_MFC_PLL_USER 14 +#define CLK_MOUT_BUS_PLL_USER 15 +#define CLK_MOUT_ACLK_HEVC_400 16 +#define CLK_MOUT_ACLK_CAM1_333 17 +#define CLK_MOUT_ACLK_CAM1_552_B 18 +#define CLK_MOUT_ACLK_CAM1_552_A 19 +#define CLK_MOUT_ACLK_ISP_DIS_400 20 +#define CLK_MOUT_ACLK_ISP_400 21 +#define CLK_MOUT_ACLK_BUS0_400 22 +#define CLK_MOUT_ACLK_MSCL_400_B 23 +#define CLK_MOUT_ACLK_MSCL_400_A 24 +#define CLK_MOUT_ACLK_GSCL_333 25 +#define CLK_MOUT_ACLK_G2D_400_B 26 +#define CLK_MOUT_ACLK_G2D_400_A 27 +#define CLK_MOUT_SCLK_JPEG_C 28 +#define CLK_MOUT_SCLK_JPEG_B 29 +#define CLK_MOUT_SCLK_JPEG_A 30 +#define CLK_MOUT_SCLK_MMC2_B 31 +#define CLK_MOUT_SCLK_MMC2_A 32 +#define CLK_MOUT_SCLK_MMC1_B 33 +#define CLK_MOUT_SCLK_MMC1_A 34 +#define CLK_MOUT_SCLK_MMC0_D 35 +#define CLK_MOUT_SCLK_MMC0_C 36 +#define CLK_MOUT_SCLK_MMC0_B 37 +#define CLK_MOUT_SCLK_MMC0_A 38 +#define CLK_MOUT_SCLK_SPI4 39 +#define CLK_MOUT_SCLK_SPI3 40 +#define CLK_MOUT_SCLK_UART2 41 +#define CLK_MOUT_SCLK_UART1 42 +#define CLK_MOUT_SCLK_UART0 43 +#define CLK_MOUT_SCLK_SPI2 44 +#define CLK_MOUT_SCLK_SPI1 45 +#define CLK_MOUT_SCLK_SPI0 46 + +#define CLK_DIV_ACLK_FSYS_200 100 +#define CLK_DIV_ACLK_IMEM_SSSX_266 101 +#define CLK_DIV_ACLK_IMEM_200 102 +#define CLK_DIV_ACLK_IMEM_266 103 +#define CLK_DIV_ACLK_PERIC_66_B 104 +#define CLK_DIV_ACLK_PERIC_66_A 105 +#define CLK_DIV_ACLK_PERIS_66_B 106 +#define CLK_DIV_ACLK_PERIS_66_A 107 +#define CLK_DIV_SCLK_MMC1_B 108 +#define CLK_DIV_SCLK_MMC1_A 109 +#define CLK_DIV_SCLK_MMC0_B 110 +#define CLK_DIV_SCLK_MMC0_A 111 +#define CLK_DIV_SCLK_MMC2_B 112 +#define CLK_DIV_SCLK_MMC2_A 113 +#define CLK_DIV_SCLK_SPI1_B 114 +#define CLK_DIV_SCLK_SPI1_A 115 +#define CLK_DIV_SCLK_SPI0_B 116 +#define CLK_DIV_SCLK_SPI0_A 117 +#define CLK_DIV_SCLK_SPI2_B 118 +#define CLK_DIV_SCLK_SPI2_A 119 +#define CLK_DIV_SCLK_UART2 120 +#define CLK_DIV_SCLK_UART1 121 +#define CLK_DIV_SCLK_UART0 122 +#define CLK_DIV_SCLK_SPI4_B 123 +#define CLK_DIV_SCLK_SPI4_A 124 +#define CLK_DIV_SCLK_SPI3_B 125 +#define CLK_DIV_SCLK_SPI3_A 126 + +#define CLK_ACLK_PERIC_66 200 +#define CLK_ACLK_PERIS_66 201 +#define CLK_ACLK_FSYS_200 202 +#define CLK_SCLK_MMC2_FSYS 203 +#define CLK_SCLK_MMC1_FSYS 204 +#define CLK_SCLK_MMC0_FSYS 205 +#define CLK_SCLK_SPI4_PERIC 206 +#define CLK_SCLK_SPI3_PERIC 207 +#define CLK_SCLK_UART2_PERIC 208 +#define CLK_SCLK_UART1_PERIC 209 +#define CLK_SCLK_UART0_PERIC 210 +#define CLK_SCLK_SPI2_PERIC 211 +#define CLK_SCLK_SPI1_PERIC 212 +#define CLK_SCLK_SPI0_PERIC 213 + +#define TOP_NR_CLK 214 + +/* CMU_CPIF */ +#define CLK_FOUT_MPHY_PLL 1 + +#define CLK_MOUT_MPHY_PLL 2 + +#define CLK_DIV_SCLK_MPHY 10 + +#define CLK_SCLK_MPHY_PLL 11 +#define CLK_SCLK_UFS_MPHY 11 + +#define CPIF_NR_CLK 12 + +/* CMU_MIF */ +#define CLK_FOUT_MEM0_PLL 1 +#define CLK_FOUT_MEM1_PLL 2 +#define CLK_FOUT_BUS_PLL 3 +#define CLK_FOUT_MFC_PLL 4 + +#define MIF_NR_CLK 5 + +/* CMU_PERIC */ +#define CLK_PCLK_SPI2 1 +#define CLK_PCLK_SPI1 2 +#define CLK_PCLK_SPI0 3 +#define CLK_PCLK_UART2 4 +#define CLK_PCLK_UART1 5 +#define CLK_PCLK_UART0 6 +#define CLK_PCLK_HSI2C3 7 +#define CLK_PCLK_HSI2C2 8 +#define CLK_PCLK_HSI2C1 9 +#define CLK_PCLK_HSI2C0 10 +#define CLK_PCLK_I2C7 11 +#define CLK_PCLK_I2C6 12 +#define CLK_PCLK_I2C5 13 +#define CLK_PCLK_I2C4 14 +#define CLK_PCLK_I2C3 15 +#define CLK_PCLK_I2C2 16 +#define CLK_PCLK_I2C1 17 +#define CLK_PCLK_I2C0 18 +#define CLK_PCLK_SPI4 19 +#define CLK_PCLK_SPI3 20 +#define CLK_PCLK_HSI2C11 21 +#define CLK_PCLK_HSI2C10 22 +#define CLK_PCLK_HSI2C9 23 +#define CLK_PCLK_HSI2C8 24 +#define CLK_PCLK_HSI2C7 25 +#define CLK_PCLK_HSI2C6 26 +#define CLK_PCLK_HSI2C5 27 +#define CLK_PCLK_HSI2C4 28 +#define CLK_SCLK_SPI4 29 +#define CLK_SCLK_SPI3 30 +#define CLK_SCLK_SPI2 31 +#define CLK_SCLK_SPI1 32 +#define CLK_SCLK_SPI0 33 +#define CLK_SCLK_UART2 34 +#define CLK_SCLK_UART1 35 +#define CLK_SCLK_UART0 36 + +#define PERIC_NR_CLK 37 + +/* CMU_PERIS */ +#define CLK_PCLK_HPM_APBIF 1 +#define CLK_PCLK_TMU1_APBIF 2 +#define CLK_PCLK_TMU0_APBIF 3 +#define CLK_PCLK_PMU_PERIS 4 +#define CLK_PCLK_SYSREG_PERIS 5 +#define CLK_PCLK_CMU_TOP_APBIF 6 +#define CLK_PCLK_WDT_APOLLO 7 +#define CLK_PCLK_WDT_ATLAS 8 +#define CLK_PCLK_MCT 9 +#define CLK_PCLK_HDMI_CEC 10 + +#define PERIS_NR_CLK 11 + +/* CMU_FSYS */ +#define CLK_MOUT_ACLK_FSYS_200_USER 1 +#define CLK_MOUT_SCLK_MMC2_USER 2 +#define CLK_MOUT_SCLK_MMC1_USER 3 +#define CLK_MOUT_SCLK_MMC0_USER 4 + +#define CLK_ACLK_PCIE 50 +#define CLK_ACLK_PDMA1 51 +#define CLK_ACLK_TSI 52 +#define CLK_ACLK_MMC2 53 +#define CLK_ACLK_MMC1 54 +#define CLK_ACLK_MMC0 55 +#define CLK_ACLK_UFS 56 +#define CLK_ACLK_USBHOST20 57 +#define CLK_ACLK_USBHOST30 58 +#define CLK_ACLK_USBDRD30 59 +#define CLK_ACLK_PDMA0 60 +#define CLK_SCLK_MMC2 61 +#define CLK_SCLK_MMC1 62 +#define CLK_SCLK_MMC0 63 +#define CLK_PDMA1 64 +#define CLK_PDMA0 65 + +#define FSYS_NR_CLK 66 + +#endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 232364969d8a8a17c52fd9b754d15924abf98d6a Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:57 +0900 Subject: clk: samsung: exynos5433: Add MUX clocks of CMU_TOP domain This patch adds the MUX (multiplexer) clocks for CMU_TOP domain of Exynos5433. CMU_TOP domain provides source clocks to other CMU domains. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 90 ++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 31 +++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index a4047390bfc2..5585dce04a38 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -208,6 +208,7 @@ PNAME(mout_mphy_pll_user_p) = { "oscclk", "sclk_mphy_pll", }; PNAME(mout_mfc_pll_user_p) = { "oscclk", "sclk_mfc_pll", }; PNAME(mout_bus_pll_user_p) = { "oscclk", "sclk_bus_pll", }; PNAME(mout_bus_pll_user_t_p) = { "oscclk", "mout_bus_pll_user", }; +PNAME(mout_mphy_pll_user_t_p) = { "oscclk", "mout_mphy_pll_user", }; PNAME(mout_bus_mfc_pll_user_p) = { "mout_bus_pll_user", "mout_mfc_pll_user",}; PNAME(mout_mfc_bus_pll_user_p) = { "mout_mfc_pll_user", "mout_bus_pll_user",}; @@ -215,6 +216,12 @@ PNAME(mout_aclk_cam1_552_b_p) = { "mout_aclk_cam1_552_a", "mout_mfc_pll_user", }; PNAME(mout_aclk_cam1_552_a_p) = { "mout_isp_pll", "mout_bus_pll_user", }; +PNAME(mout_aclk_mfc_400_c_p) = { "mout_aclk_mfc_400_b", + "mout_mphy_pll_user", }; +PNAME(mout_aclk_mfc_400_b_p) = { "mout_aclk_mfc_400_a", + "mout_bus_pll_user", }; +PNAME(mout_aclk_mfc_400_a_p) = { "mout_mfc_pll_user", "mout_isp_pll", }; + PNAME(mout_bus_mphy_pll_user_p) = { "mout_bus_pll_user", "mout_mphy_pll_user", }; PNAME(mout_aclk_mscl_b_p) = { "mout_aclk_mscl_400_a", @@ -231,6 +238,21 @@ PNAME(mout_sclk_mmc0_d_p) = { "mout_sclk_mmc0_c", "mout_isp_pll", }; PNAME(mout_sclk_mmc0_c_p) = { "mout_sclk_mmc0_b", "mout_mphy_pll_user",}; PNAME(mout_sclk_mmc0_b_p) = { "mout_sclk_mmc0_a", "mout_mfc_pll_user", }; +PNAME(mout_sclk_spdif_p) = { "sclk_audio0", "sclk_audio1", + "oscclk", "ioclk_spdif_extclk", }; +PNAME(mout_sclk_audio1_p) = { "ioclk_audiocdclk1", "oscclk", + "mout_aud_pll_user_t",}; +PNAME(mout_sclk_audio0_p) = { "ioclk_audiocdclk0", "oscclk", + "mout_aud_pll_user_t",}; + +static struct samsung_fixed_rate_clock top_fixed_clks[] __initdata = { + /* Xi2s{0|1}CDCLK input clock for I2S/PCM */ + FRATE(0, "ioclk_audiocdclk1", NULL, CLK_IS_ROOT, 100000000), + FRATE(0, "ioclk_audiocdclk0", NULL, CLK_IS_ROOT, 100000000), + /* Xi2s1SDI input clock for SPDIF */ + FRATE(0, "ioclk_spdif_extclk", NULL, CLK_IS_ROOT, 100000000), +}; + static struct samsung_mux_clock top_mux_clks[] __initdata = { /* MUX_SEL_TOP0 */ MUX(CLK_MOUT_AUD_PLL, "mout_aud_pll", mout_aud_pll_p, MUX_SEL_TOP0, @@ -276,6 +298,14 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX(CLK_MOUT_ACLK_G2D_400_A, "mout_aclk_g2d_400_a", mout_bus_mfc_pll_user_p, MUX_SEL_TOP3, 0, 1), + /* MUX_SEL_TOP4 */ + MUX(CLK_MOUT_ACLK_MFC_400_C, "mout_aclk_mfc_400_c", + mout_aclk_mfc_400_c_p, MUX_SEL_TOP4, 8, 1), + MUX(CLK_MOUT_ACLK_MFC_400_B, "mout_aclk_mfc_400_b", + mout_aclk_mfc_400_b_p, MUX_SEL_TOP4, 4, 1), + MUX(CLK_MOUT_ACLK_MFC_400_A, "mout_aclk_mfc_400_a", + mout_aclk_mfc_400_a_p, MUX_SEL_TOP4, 0, 1), + /* MUX_SEL_TOP_MSCL */ MUX(CLK_MOUT_SCLK_JPEG_C, "mout_sclk_jpeg_c", mout_sclk_jpeg_c_p, MUX_SEL_TOP_MSCL, 8, 1), @@ -284,6 +314,20 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX(CLK_MOUT_SCLK_JPEG_A, "mout_sclk_jpeg_a", mout_bus_pll_user_t_p, MUX_SEL_TOP_MSCL, 0, 1), + /* MUX_SEL_TOP_CAM1 */ + MUX(CLK_MOUT_SCLK_ISP_SENSOR2, "mout_sclk_isp_sensor2", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 24, 1), + MUX(CLK_MOUT_SCLK_ISP_SENSOR1, "mout_sclk_isp_sensor1", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 20, 1), + MUX(CLK_MOUT_SCLK_ISP_SENSOR0, "mout_sclk_isp_sensor0", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 16, 1), + MUX(CLK_MOUT_SCLK_ISP_UART, "mout_sclk_isp_uart", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 8, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI1, "mout_sclk_isp_spi1", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 4, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI0, "mout_sclk_isp_spi0", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 0, 1), + /* MUX_SEL_TOP_FSYS0 */ MUX(CLK_MOUT_SCLK_MMC2_B, "mout_sclk_mmc2_b", mout_sclk_mmc2_b_p, MUX_SEL_TOP_FSYS0, 28, 1), @@ -302,6 +346,16 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX(CLK_MOUT_SCLK_MMC0_A, "mout_sclk_mmc0_a", mout_bus_pll_user_t_p, MUX_SEL_TOP_FSYS0, 0, 1), + /* MUX_SEL_TOP_FSYS1 */ + MUX(CLK_MOUT_SCLK_PCIE_100, "mout_sclk_pcie_100", mout_bus_pll_user_t_p, + MUX_SEL_TOP_FSYS1, 12, 1), + MUX(CLK_MOUT_SCLK_UFSUNIPRO, "mout_sclk_ufsunipro", + mout_mphy_pll_user_t_p, MUX_SEL_TOP_FSYS1, 8, 1), + MUX(CLK_MOUT_SCLK_USBHOST30, "mout_sclk_usbhost30", + mout_bus_pll_user_t_p, MUX_SEL_TOP_FSYS1, 4, 1), + MUX(CLK_MOUT_SCLK_USBDRD30, "mout_sclk_usbdrd30", + mout_bus_pll_user_t_p, MUX_SEL_TOP_FSYS1, 0, 1), + /* MUX_SEL_TOP_PERIC0 */ MUX(CLK_MOUT_SCLK_SPI4, "mout_sclk_spi4", mout_bus_pll_user_t_p, MUX_SEL_TOP_PERIC0, 28, 1), @@ -319,6 +373,16 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX_SEL_TOP_PERIC0, 4, 1), MUX(CLK_MOUT_SCLK_SPI0, "mout_sclk_spi0", mout_bus_pll_user_t_p, MUX_SEL_TOP_PERIC0, 0, 1), + + /* MUX_SEL_TOP_PERIC1 */ + MUX(CLK_MOUT_SCLK_SLIMBUS, "mout_sclk_slimbus", mout_aud_pll_user_p, + MUX_SEL_TOP_PERIC1, 16, 1), + MUX(CLK_MOUT_SCLK_SPDIF, "mout_sclk_spdif", mout_sclk_spdif_p, + MUX_SEL_TOP_PERIC1, 12, 2), + MUX(CLK_MOUT_SCLK_AUDIO1, "mout_sclk_audio1", mout_sclk_audio1_p, + MUX_SEL_TOP_PERIC1, 4, 2), + MUX(CLK_MOUT_SCLK_AUDIO0, "mout_sclk_audio0", mout_sclk_audio0_p, + MUX_SEL_TOP_PERIC1, 0, 2), }; static struct samsung_div_clock top_div_clks[] __initdata = { @@ -382,6 +446,16 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_SCLK_UART0, "div_sclk_uart0", "mout_sclk_uart1", DIV_TOP_PERIC2, 0, 4), + /* DIV_TOP_PERIC3 */ + DIV(CLK_DIV_SCLK_I2S1, "div_sclk_i2s1", "sclk_audio1", + DIV_TOP_PERIC3, 16, 6), + DIV(CLK_DIV_SCLK_PCM1, "div_sclk_pcm1", "sclk_audio1", + DIV_TOP_PERIC3, 8, 8), + DIV(CLK_DIV_SCLK_AUDIO1, "div_sclk_audio1", "mout_sclk_audio1", + DIV_TOP_PERIC3, 4, 4), + DIV(CLK_DIV_SCLK_AUDIO0, "div_sclk_audio0", "mout_sclk_audio0", + DIV_TOP_PERIC3, 0, 4), + /* DIV_TOP_PERIC4 */ DIV(CLK_DIV_SCLK_SPI4_B, "div_sclk_spi4_b", "div_sclk_spi4_a", DIV_TOP_PERIC4, 16, 8), @@ -418,6 +492,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { ENABLE_SCLK_TOP_PERIC, 12, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI3_PERIC, "sclk_spi3_peric", "div_sclk_spi3_b", ENABLE_SCLK_TOP_PERIC, 11, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPDIF_PERIC, "sclk_spdif_peric", "mout_sclk_spdif", + ENABLE_SCLK_TOP_PERIC, 9, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_I2S1_PERIC, "sclk_i2s1_peric", "div_sclk_i2s1", + ENABLE_SCLK_TOP_PERIC, 8, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_PCM1_PERIC, "sclk_pcm1_peric", "div_sclk_pcm1", + ENABLE_SCLK_TOP_PERIC, 7, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_UART2_PERIC, "sclk_uart2_peric", "div_sclk_uart2", ENABLE_SCLK_TOP_PERIC, 5, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_UART1_PERIC, "sclk_uart1_peric", "div_sclk_uart1", @@ -430,6 +510,14 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { ENABLE_SCLK_TOP_PERIC, 1, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI0_PERIC, "sclk_spi0_peric", "div_sclk_spi0_b", ENABLE_SCLK_TOP_PERIC, 0, CLK_SET_RATE_PARENT, 0), + + /* MUX_ENABLE_TOP_PERIC1 */ + GATE(CLK_SCLK_SLIMBUS, "sclk_slimbus", "mout_sclk_slimbus", + MUX_ENABLE_TOP_PERIC1, 16, 0, 0), + GATE(CLK_SCLK_AUDIO1, "sclk_audio1", "div_sclk_audio1", + MUX_ENABLE_TOP_PERIC1, 4, 0, 0), + GATE(CLK_SCLK_AUDIO0, "sclk_audio0", "div_sclk_audio0", + MUX_ENABLE_TOP_PERIC1, 0, 0, 0), }; /* @@ -516,6 +604,8 @@ static struct samsung_cmu_info top_cmu_info __initdata = { .nr_div_clks = ARRAY_SIZE(top_div_clks), .gate_clks = top_gate_clks, .nr_gate_clks = ARRAY_SIZE(top_gate_clks), + .fixed_clks = top_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(top_fixed_clks), .nr_clk_ids = TOP_NR_CLK, .clk_regs = top_clk_regs, .nr_clk_regs = ARRAY_SIZE(top_clk_regs), diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 5c4e2e39ce49..8f0ee5a13db4 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -51,6 +51,23 @@ #define CLK_MOUT_SCLK_SPI2 44 #define CLK_MOUT_SCLK_SPI1 45 #define CLK_MOUT_SCLK_SPI0 46 +#define CLK_MOUT_ACLK_MFC_400_C 47 +#define CLK_MOUT_ACLK_MFC_400_B 48 +#define CLK_MOUT_ACLK_MFC_400_A 49 +#define CLK_MOUT_SCLK_ISP_SENSOR2 50 +#define CLK_MOUT_SCLK_ISP_SENSOR1 51 +#define CLK_MOUT_SCLK_ISP_SENSOR0 52 +#define CLK_MOUT_SCLK_ISP_UART 53 +#define CLK_MOUT_SCLK_ISP_SPI1 54 +#define CLK_MOUT_SCLK_ISP_SPI0 55 +#define CLK_MOUT_SCLK_PCIE_100 56 +#define CLK_MOUT_SCLK_UFSUNIPRO 57 +#define CLK_MOUT_SCLK_USBHOST30 58 +#define CLK_MOUT_SCLK_USBDRD30 59 +#define CLK_MOUT_SCLK_SLIMBUS 60 +#define CLK_MOUT_SCLK_SPDIF 61 +#define CLK_MOUT_SCLK_AUDIO1 62 +#define CLK_MOUT_SCLK_AUDIO0 63 #define CLK_DIV_ACLK_FSYS_200 100 #define CLK_DIV_ACLK_IMEM_SSSX_266 101 @@ -79,6 +96,10 @@ #define CLK_DIV_SCLK_SPI4_A 124 #define CLK_DIV_SCLK_SPI3_B 125 #define CLK_DIV_SCLK_SPI3_A 126 +#define CLK_DIV_SCLK_I2S1 127 +#define CLK_DIV_SCLK_PCM1 128 +#define CLK_DIV_SCLK_AUDIO1 129 +#define CLK_DIV_SCLK_AUDIO0 130 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -94,8 +115,14 @@ #define CLK_SCLK_SPI2_PERIC 211 #define CLK_SCLK_SPI1_PERIC 212 #define CLK_SCLK_SPI0_PERIC 213 - -#define TOP_NR_CLK 214 +#define CLK_SCLK_SPDIF_PERIC 214 +#define CLK_SCLK_I2S1_PERIC 215 +#define CLK_SCLK_PCM1_PERIC 216 +#define CLK_SCLK_SLIMBUS 217 +#define CLK_SCLK_AUDIO1 218 +#define CLK_SCLK_AUDIO0 219 + +#define TOP_NR_CLK 220 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 -- cgit v1.2.3 From d0f5de6677de4405c9acdb88db7c7cf7b9cc954e Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:58 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_PERIC domain This patch adds missing divider/gate clocks of CMU_PERIC domain which includes I2S/PCM/SPDIF/PWM/SLIMBUS IPs. The SPI/I2S may use external input clock which has 'ioclk_*' prefix. Signed-off-by: Chanwoo Choi [ideal.song: Change clk flags of to pclk_gpio_* clk, pclk_gpio_* should be always on] Signed-off-by: Inha Song Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 83 +++++++++++++++++++++++++++++++++- include/dt-bindings/clock/exynos5433.h | 34 +++++++++++++- 2 files changed, 114 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 5585dce04a38..10a9f8313c24 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -251,6 +251,14 @@ static struct samsung_fixed_rate_clock top_fixed_clks[] __initdata = { FRATE(0, "ioclk_audiocdclk0", NULL, CLK_IS_ROOT, 100000000), /* Xi2s1SDI input clock for SPDIF */ FRATE(0, "ioclk_spdif_extclk", NULL, CLK_IS_ROOT, 100000000), + /* XspiCLK[4:0] input clock for SPI */ + FRATE(0, "ioclk_spi4_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi3_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi2_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi1_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi0_clk_in", NULL, CLK_IS_ROOT, 50000000), + /* Xi2s1SCLK input clock for I2S1_BCLK */ + FRATE(0, "ioclk_i2s1_bclk_in", NULL, CLK_IS_ROOT, 12288000), }; static struct samsung_mux_clock top_mux_clks[] __initdata = { @@ -756,6 +764,7 @@ CLK_OF_DECLARE(exynos5433_cmu_mif, "samsung,exynos5433-cmu-mif", * Register offset definitions for CMU_PERIC */ #define DIV_PERIC 0x0600 +#define DIV_STAT_PERIC 0x0700 #define ENABLE_ACLK_PERIC 0x0800 #define ENABLE_PCLK_PERIC0 0x0900 #define ENABLE_PCLK_PERIC1 0x0904 @@ -766,6 +775,7 @@ CLK_OF_DECLARE(exynos5433_cmu_mif, "samsung,exynos5433-cmu-mif", static unsigned long peric_clk_regs[] __initdata = { DIV_PERIC, + DIV_STAT_PERIC, ENABLE_ACLK_PERIC, ENABLE_PCLK_PERIC0, ENABLE_PCLK_PERIC1, @@ -775,14 +785,57 @@ static unsigned long peric_clk_regs[] __initdata = { ENABLE_IP_PERIC2, }; +static struct samsung_div_clock peric_div_clks[] __initdata = { + /* DIV_PERIC */ + DIV(CLK_DIV_SCLK_SCI, "div_sclk_sci", "oscclk", DIV_PERIC, 4, 4), + DIV(CLK_DIV_SCLK_SC_IN, "div_sclk_sc_in", "oscclk", DIV_PERIC, 0, 4), +}; + static struct samsung_gate_clock peric_gate_clks[] __initdata = { + /* ENABLE_ACLK_PERIC */ + GATE(CLK_ACLK_AHB2APB_PERIC2P, "aclk_ahb2apb_peric2p", "aclk_peric_66", + ENABLE_ACLK_PERIC, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_PERIC1P, "aclk_ahb2apb_peric1p", "aclk_peric_66", + ENABLE_ACLK_PERIC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_PERIC0P, "aclk_ahb2apb_peric0p", "aclk_peric_66", + ENABLE_ACLK_PERIC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PERICNP_66, "aclk_pericnp_66", "aclk_peric_66", + ENABLE_ACLK_PERIC, 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_PCLK_PERIC0 */ + GATE(CLK_PCLK_SCI, "pclk_sci", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 31, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_GPIO_FINGER, "pclk_gpio_finger", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 30, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_ESE, "pclk_gpio_ese", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PWM, "pclk_pwm", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 28, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_SPDIF, "pclk_spdif", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 26, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_PCM1, "pclk_pcm1", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 25, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2S1, "pclk_i2s", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 24, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_SPI2, "pclk_spi2", "aclk_peric_66", ENABLE_PCLK_PERIC0, 23, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_SPI1, "pclk_spi1", "aclk_peric_66", ENABLE_PCLK_PERIC0, 22, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_SPI0, "pclk_spi0", "aclk_peric_66", ENABLE_PCLK_PERIC0, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_ADCIF, "pclk_adcif", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 20, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_GPIO_TOUCH, "pclk_gpio_touch", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_NFC, "pclk_gpio_nfc", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_PERIC, "pclk_gpio_peric", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_PERIC, "pclk_pmu_peric", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 16, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_SYSREG_PERIC, "pclk_sysreg_peric", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 15, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_PCLK_UART2, "pclk_uart2", "aclk_peric_66", ENABLE_PCLK_PERIC0, 14, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_UART1, "pclk_uart1", "aclk_peric_66", ENABLE_PCLK_PERIC0, @@ -837,15 +890,39 @@ static struct samsung_gate_clock peric_gate_clks[] __initdata = { ENABLE_PCLK_PERIC1, 0, CLK_SET_RATE_PARENT, 0), /* ENABLE_SCLK_PERIC */ + GATE(CLK_SCLK_IOCLK_SPI4, "sclk_ioclk_spi4", "ioclk_spi4_clk_in", + ENABLE_SCLK_PERIC, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_SPI3, "sclk_ioclk_spi3", "ioclk_spi3_clk_in", + ENABLE_SCLK_PERIC, 20, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI4, "sclk_spi4", "sclk_spi4_peric", ENABLE_SCLK_PERIC, 19, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI3, "sclk_spi3", "sclk_spi3_peric", ENABLE_SCLK_PERIC, 18, CLK_SET_RATE_PARENT, 0), - + GATE(CLK_SCLK_SCI, "sclk_sci", "div_sclk_sci", ENABLE_SCLK_PERIC, + 17, 0, 0), + GATE(CLK_SCLK_SC_IN, "sclk_sc_in", "div_sclk_sc_in", ENABLE_SCLK_PERIC, + 16, 0, 0), + GATE(CLK_SCLK_PWM, "sclk_pwm", "oscclk", ENABLE_SCLK_PERIC, 15, 0, 0), + GATE(CLK_SCLK_IOCLK_SPI2, "sclk_ioclk_spi2", "ioclk_spi2_clk_in", + ENABLE_SCLK_PERIC, 13, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_SPI1, "sclk_ioclk_spi1", "ioclk_spi1_clk_in", + ENABLE_SCLK_PERIC, 12, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_SPI0, "sclk_ioclk_spi0", "ioclk_spi0_clk_in", + ENABLE_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_I2S1_BCLK, "sclk_ioclk_i2s1_bclk", + "ioclk_i2s1_bclk_in", ENABLE_SCLK_PERIC, 10, + CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPDIF, "sclk_spdif", "sclk_spdif_peric", + ENABLE_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric", + ENABLE_SCLK_PERIC, 7, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_I2S1, "sclk_i2s1", "sclk_i2s1_peric", + ENABLE_SCLK_PERIC, 6, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI2, "sclk_spi2", "sclk_spi2_peric", ENABLE_SCLK_PERIC, 5, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI1, "sclk_spi1", "sclk_spi1_peric", ENABLE_SCLK_PERIC, - 4, CLK_SET_RATE_PARENT, 0), + 4, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI0, "sclk_spi0", "sclk_spi0_peric", ENABLE_SCLK_PERIC, 3, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_UART2, "sclk_uart2", "sclk_uart2_peric", @@ -857,6 +934,8 @@ static struct samsung_gate_clock peric_gate_clks[] __initdata = { }; static struct samsung_cmu_info peric_cmu_info __initdata = { + .div_clks = peric_div_clks, + .nr_div_clks = ARRAY_SIZE(peric_div_clks), .gate_clks = peric_gate_clks, .nr_gate_clks = ARRAY_SIZE(peric_gate_clks), .nr_clk_ids = PERIC_NR_CLK, diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 8f0ee5a13db4..b5c66f7b83be 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -181,8 +181,40 @@ #define CLK_SCLK_UART2 34 #define CLK_SCLK_UART1 35 #define CLK_SCLK_UART0 36 +#define CLK_ACLK_AHB2APB_PERIC2P 37 +#define CLK_ACLK_AHB2APB_PERIC1P 38 +#define CLK_ACLK_AHB2APB_PERIC0P 39 +#define CLK_ACLK_PERICNP_66 40 +#define CLK_PCLK_SCI 41 +#define CLK_PCLK_GPIO_FINGER 42 +#define CLK_PCLK_GPIO_ESE 43 +#define CLK_PCLK_PWM 44 +#define CLK_PCLK_SPDIF 45 +#define CLK_PCLK_PCM1 46 +#define CLK_PCLK_I2S1 47 +#define CLK_PCLK_ADCIF 48 +#define CLK_PCLK_GPIO_TOUCH 49 +#define CLK_PCLK_GPIO_NFC 50 +#define CLK_PCLK_GPIO_PERIC 51 +#define CLK_PCLK_PMU_PERIC 52 +#define CLK_PCLK_SYSREG_PERIC 53 +#define CLK_SCLK_IOCLK_SPI4 54 +#define CLK_SCLK_IOCLK_SPI3 55 +#define CLK_SCLK_SCI 56 +#define CLK_SCLK_SC_IN 57 +#define CLK_SCLK_PWM 58 +#define CLK_SCLK_IOCLK_SPI2 59 +#define CLK_SCLK_IOCLK_SPI1 60 +#define CLK_SCLK_IOCLK_SPI0 61 +#define CLK_SCLK_IOCLK_I2S1_BCLK 62 +#define CLK_SCLK_SPDIF 63 +#define CLK_SCLK_PCM1 64 +#define CLK_SCLK_I2S1 65 -#define PERIC_NR_CLK 37 +#define CLK_DIV_SCLK_SCI 70 +#define CLK_DIV_SCLK_SC_IN 71 + +#define PERIC_NR_CLK 72 /* CMU_PERIS */ #define CLK_PCLK_HPM_APBIF 1 -- cgit v1.2.3 From 56bcf3f3ea39402acff09cba9558a0d3b13fc56f Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:59 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_PERIS domain This patch adds missing gate clocks of CMU_PERIS domain which includes TMU/TZPC/SECKEY/CHIPID/TOPRTC/EFUSE IPs. The special clocks of CMU_PERIS use oscclk source clock directly. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 151 ++++++++++++++++++++++++++++++++- include/dt-bindings/clock/exynos5433.h | 33 ++++++- 2 files changed, 181 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 10a9f8313c24..5ba9311624aa 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -245,6 +245,10 @@ PNAME(mout_sclk_audio1_p) = { "ioclk_audiocdclk1", "oscclk", PNAME(mout_sclk_audio0_p) = { "ioclk_audiocdclk0", "oscclk", "mout_aud_pll_user_t",}; +static struct samsung_fixed_factor_clock top_fixed_factor_clks[] __initdata = { + FFACTOR(0, "oscclk_efuse_common", "oscclk", 1, 1, 0), +}; + static struct samsung_fixed_rate_clock top_fixed_clks[] __initdata = { /* Xi2s{0|1}CDCLK input clock for I2S/PCM */ FRATE(0, "ioclk_audiocdclk1", NULL, CLK_IS_ROOT, 100000000), @@ -614,6 +618,8 @@ static struct samsung_cmu_info top_cmu_info __initdata = { .nr_gate_clks = ARRAY_SIZE(top_gate_clks), .fixed_clks = top_fixed_clks, .nr_fixed_clks = ARRAY_SIZE(top_fixed_clks), + .fixed_factor_clks = top_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(top_fixed_factor_clks), .nr_clk_ids = TOP_NR_CLK, .clk_regs = top_clk_regs, .nr_clk_regs = ARRAY_SIZE(top_clk_regs), @@ -954,15 +960,69 @@ CLK_OF_DECLARE(exynos5433_cmu_peric, "samsung,exynos5433-cmu-peric", /* * Register offset definitions for CMU_PERIS */ -#define ENABLE_ACLK_PERIS 0x0800 -#define ENABLE_PCLK_PERIS 0x0900 +#define ENABLE_ACLK_PERIS 0x0800 +#define ENABLE_PCLK_PERIS 0x0900 +#define ENABLE_PCLK_PERIS_SECURE_TZPC 0x0904 +#define ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF 0x0908 +#define ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF 0x090c +#define ENABLE_PCLK_PERIS_SECURE_TOPRTC 0x0910 +#define ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF 0x0914 +#define ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF 0x0918 +#define ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF 0x091c +#define ENABLE_SCLK_PERIS 0x0a00 +#define ENABLE_SCLK_PERIS_SECURE_SECKEY 0x0a04 +#define ENABLE_SCLK_PERIS_SECURE_CHIPID 0x0a08 +#define ENABLE_SCLK_PERIS_SECURE_TOPRTC 0x0a0c +#define ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE 0x0a10 +#define ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT 0x0a14 +#define ENABLE_SCLK_PERIS_SECURE_OTP_CON 0x0a18 +#define ENABLE_IP_PERIS0 0x0b00 +#define ENABLE_IP_PERIS1 0x0b04 +#define ENABLE_IP_PERIS_SECURE_TZPC 0x0b08 +#define ENABLE_IP_PERIS_SECURE_SECKEY 0x0b0c +#define ENABLE_IP_PERIS_SECURE_CHIPID 0x0b10 +#define ENABLE_IP_PERIS_SECURE_TOPRTC 0x0b14 +#define ENABLE_IP_PERIS_SECURE_CUSTOM_EFUSE 0x0b18 +#define ENABLE_IP_PERIS_SECURE_ANTIBRK_CNT 0x0b1c +#define ENABLE_IP_PERIS_SECURE_OTP_CON 0x0b20 static unsigned long peris_clk_regs[] __initdata = { ENABLE_ACLK_PERIS, ENABLE_PCLK_PERIS, + ENABLE_PCLK_PERIS_SECURE_TZPC, + ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF, + ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF, + ENABLE_PCLK_PERIS_SECURE_TOPRTC, + ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF, + ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF, + ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF, + ENABLE_SCLK_PERIS, + ENABLE_SCLK_PERIS_SECURE_SECKEY, + ENABLE_SCLK_PERIS_SECURE_CHIPID, + ENABLE_SCLK_PERIS_SECURE_TOPRTC, + ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE, + ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT, + ENABLE_SCLK_PERIS_SECURE_OTP_CON, + ENABLE_IP_PERIS0, + ENABLE_IP_PERIS1, + ENABLE_IP_PERIS_SECURE_TZPC, + ENABLE_IP_PERIS_SECURE_SECKEY, + ENABLE_IP_PERIS_SECURE_CHIPID, + ENABLE_IP_PERIS_SECURE_TOPRTC, + ENABLE_IP_PERIS_SECURE_CUSTOM_EFUSE, + ENABLE_IP_PERIS_SECURE_ANTIBRK_CNT, + ENABLE_IP_PERIS_SECURE_OTP_CON, }; static struct samsung_gate_clock peris_gate_clks[] __initdata = { + /* ENABLE_ACLK_PERIS */ + GATE(CLK_ACLK_AHB2APB_PERIS1P, "aclk_ahb2apb_peris1p", "aclk_peris_66", + ENABLE_ACLK_PERIS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_PERIS0P, "aclk_ahb2apb_peris0p", "aclk_peris_66", + ENABLE_ACLK_PERIS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PERISNP_66, "aclk_perisnp_66", "aclk_peris_66", + ENABLE_ACLK_PERIS, 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_PCLK_PERIS */ GATE(CLK_PCLK_HPM_APBIF, "pclk_hpm_apbif", "aclk_peris_66", ENABLE_PCLK_PERIS, 30, CLK_IGNORE_UNUSED, 0), @@ -984,6 +1044,93 @@ static struct samsung_gate_clock peris_gate_clks[] __initdata = { ENABLE_PCLK_PERIS, 15, CLK_IGNORE_UNUSED, 0), GATE(CLK_PCLK_HDMI_CEC, "pclk_hdmi_cec", "aclk_peris_66", ENABLE_PCLK_PERIS, 14, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_PERIS_SECURE_TZPC */ + GATE(CLK_PCLK_TZPC12, "pclk_tzpc12", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 12, 0, 0), + GATE(CLK_PCLK_TZPC11, "pclk_tzpc11", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 11, 0, 0), + GATE(CLK_PCLK_TZPC10, "pclk_tzpc10", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 10, 0, 0), + GATE(CLK_PCLK_TZPC9, "pclk_tzpc9", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 9, 0, 0), + GATE(CLK_PCLK_TZPC8, "pclk_tzpc8", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 8, 0, 0), + GATE(CLK_PCLK_TZPC7, "pclk_tzpc7", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 7, 0, 0), + GATE(CLK_PCLK_TZPC6, "pclk_tzpc6", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 6, 0, 0), + GATE(CLK_PCLK_TZPC5, "pclk_tzpc5", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 5, 0, 0), + GATE(CLK_PCLK_TZPC4, "pclk_tzpc4", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 4, 0, 0), + GATE(CLK_PCLK_TZPC3, "pclk_tzpc3", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 3, 0, 0), + GATE(CLK_PCLK_TZPC2, "pclk_tzpc2", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 2, 0, 0), + GATE(CLK_PCLK_TZPC1, "pclk_tzpc1", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 1, 0, 0), + GATE(CLK_PCLK_TZPC0, "pclk_tzpc0", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF */ + GATE(CLK_PCLK_SECKEY_APBIF, "pclk_seckey_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF */ + GATE(CLK_PCLK_CHIPID_APBIF, "pclk_chipid_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_TOPRTC */ + GATE(CLK_PCLK_TOPRTC, "pclk_toprtc", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TOPRTC, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF */ + GATE(CLK_PCLK_CUSTOM_EFUSE_APBIF, "pclk_custom_efuse_apbif", + "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF */ + GATE(CLK_PCLK_ANTIRBK_CNT_APBIF, "pclk_antirbk_cnt_apbif", + "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF */ + GATE(CLK_PCLK_OTP_CON_APBIF, "pclk_otp_con_apbif", + "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF, 0, 0, 0), + + /* ENABLE_SCLK_PERIS */ + GATE(CLK_SCLK_ASV_TB, "sclk_asv_tb", "oscclk_efuse_common", + ENABLE_SCLK_PERIS, 10, 0, 0), + GATE(CLK_SCLK_TMU1, "sclk_tmu1", "oscclk_efuse_common", + ENABLE_SCLK_PERIS, 4, 0, 0), + GATE(CLK_SCLK_TMU0, "sclk_tmu0", "oscclk_efuse_common", + ENABLE_SCLK_PERIS, 3, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_SECKEY */ + GATE(CLK_SCLK_SECKEY, "sclk_seckey", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_SECKEY, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_CHIPID */ + GATE(CLK_SCLK_CHIPID, "sclk_chipid", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_CHIPID, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_TOPRTC */ + GATE(CLK_SCLK_TOPRTC, "sclk_toprtc", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_TOPRTC, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE */ + GATE(CLK_SCLK_CUSTOM_EFUSE, "sclk_custom_efuse", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT */ + GATE(CLK_SCLK_ANTIRBK_CNT, "sclk_antirbk_cnt", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_OTP_CON */ + GATE(CLK_SCLK_OTP_CON, "sclk_otp_con", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_OTP_CON, 0, 0, 0), }; static struct samsung_cmu_info peris_cmu_info __initdata = { diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index b5c66f7b83be..5b3397d9843a 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -227,8 +227,39 @@ #define CLK_PCLK_WDT_ATLAS 8 #define CLK_PCLK_MCT 9 #define CLK_PCLK_HDMI_CEC 10 +#define CLK_ACLK_AHB2APB_PERIS1P 11 +#define CLK_ACLK_AHB2APB_PERIS0P 12 +#define CLK_ACLK_PERISNP_66 13 +#define CLK_PCLK_TZPC12 14 +#define CLK_PCLK_TZPC11 15 +#define CLK_PCLK_TZPC10 16 +#define CLK_PCLK_TZPC9 17 +#define CLK_PCLK_TZPC8 18 +#define CLK_PCLK_TZPC7 19 +#define CLK_PCLK_TZPC6 20 +#define CLK_PCLK_TZPC5 21 +#define CLK_PCLK_TZPC4 22 +#define CLK_PCLK_TZPC3 23 +#define CLK_PCLK_TZPC2 24 +#define CLK_PCLK_TZPC1 25 +#define CLK_PCLK_TZPC0 26 +#define CLK_PCLK_SECKEY_APBIF 27 +#define CLK_PCLK_CHIPID_APBIF 28 +#define CLK_PCLK_TOPRTC 29 +#define CLK_PCLK_CUSTOM_EFUSE_APBIF 30 +#define CLK_PCLK_ANTIRBK_CNT_APBIF 31 +#define CLK_PCLK_OTP_CON_APBIF 32 +#define CLK_SCLK_ASV_TB 33 +#define CLK_SCLK_TMU1 34 +#define CLK_SCLK_TMU0 35 +#define CLK_SCLK_SECKEY 36 +#define CLK_SCLK_CHIPID 37 +#define CLK_SCLK_TOPRTC 38 +#define CLK_SCLK_CUSTOM_EFUSE 39 +#define CLK_SCLK_ANTIRBK_CNT 40 +#define CLK_SCLK_OTP_CON 41 -#define PERIS_NR_CLK 11 +#define PERIS_NR_CLK 42 /* CMU_FSYS */ #define CLK_MOUT_ACLK_FSYS_200_USER 1 -- cgit v1.2.3 From a29308dad5dc4695a344ed9042cae8a1b8e35267 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:00 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_G2D domain This patch adds ths mux/divider/gate clocks of CMU_G2D domain which includes G2D/MDMA IPs. The CMU_G2D requires its parent defined in the CMU_TOP domain. Hence this patch adds G2D related clocks to the CMU_TOP domain. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 146 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 42 +++++++++- 2 files changed, 187 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 5ba9311624aa..24218dba8218 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -398,6 +398,20 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { }; static struct samsung_div_clock top_div_clks[] __initdata = { + /* DIV_TOP1 */ + DIV(CLK_DIV_ACLK_GSCL_111, "div_aclk_gscl_111", "mout_aclk_gscl_333", + DIV_TOP1, 28, 3), + DIV(CLK_DIV_ACLK_GSCL_333, "div_aclk_gscl_333", "mout_aclk_gscl_333", + DIV_TOP1, 24, 3), + DIV(CLK_DIV_ACLK_HEVC_400, "div_aclk_hevc_400", "mout_aclk_hevc_400", + DIV_TOP1, 20, 3), + DIV(CLK_DIV_ACLK_MFC_400, "div_aclk_mfc_400", "mout_aclk_mfc_400_c", + DIV_TOP1, 12, 3), + DIV(CLK_DIV_ACLK_G2D_266, "div_aclk_g2d_266", "mout_bus_pll_user", + DIV_TOP1, 8, 3), + DIV(CLK_DIV_ACLK_G2D_400, "div_aclk_g2d_400", "mout_aclk_g2d_400_b", + DIV_TOP1, 0, 3), + /* DIV_TOP2 */ DIV(CLK_DIV_ACLK_FSYS_200, "div_aclk_fsys_200", "mout_bus_pll_user", DIV_TOP2, 0, 3), @@ -490,6 +504,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_FSYS_200, "aclk_fsys_200", "div_aclk_fsys_200", ENABLE_ACLK_TOP, 18, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2D_266, "aclk_g2d_266", "div_aclk_g2d_266", + ENABLE_ACLK_TOP, 2, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2D_400, "aclk_g2d_400", "div_aclk_g2d_400", + ENABLE_ACLK_TOP, 0, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_MMC2_FSYS, "sclk_mmc2_fsys", "div_sclk_mmc2_b", @@ -1277,3 +1297,129 @@ static void __init exynos5433_cmu_fsys_init(struct device_node *np) CLK_OF_DECLARE(exynos5433_cmu_fsys, "samsung,exynos5433-cmu-fsys", exynos5433_cmu_fsys_init); + +/* + * Register offset definitions for CMU_G2D + */ +#define MUX_SEL_G2D0 0x0200 +#define MUX_SEL_ENABLE_G2D0 0x0300 +#define MUX_SEL_STAT_G2D0 0x0400 +#define DIV_G2D 0x0600 +#define DIV_STAT_G2D 0x0700 +#define DIV_ENABLE_ACLK_G2D 0x0800 +#define DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D 0x0804 +#define DIV_ENABLE_PCLK_G2D 0x0900 +#define DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D 0x0904 +#define DIV_ENABLE_IP_G2D0 0x0b00 +#define DIV_ENABLE_IP_G2D1 0x0b04 +#define DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D 0x0b08 + +static unsigned long g2d_clk_regs[] __initdata = { + MUX_SEL_G2D0, + MUX_SEL_ENABLE_G2D0, + MUX_SEL_STAT_G2D0, + DIV_G2D, + DIV_STAT_G2D, + DIV_ENABLE_ACLK_G2D, + DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D, + DIV_ENABLE_PCLK_G2D, + DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D, + DIV_ENABLE_IP_G2D0, + DIV_ENABLE_IP_G2D1, + DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D, +}; + +/* list of all parent clock list */ +PNAME(mout_aclk_g2d_266_user_p) = { "oscclk", "aclk_g2d_266", }; +PNAME(mout_aclk_g2d_400_user_p) = { "oscclk", "aclk_g2d_400", }; + +static struct samsung_mux_clock g2d_mux_clks[] __initdata = { + /* MUX_SEL_G2D0 */ + MUX(CLK_MUX_ACLK_G2D_266_USER, "mout_aclk_g2d_266_user", + mout_aclk_g2d_266_user_p, MUX_SEL_G2D0, 4, 1), + MUX(CLK_MUX_ACLK_G2D_400_USER, "mout_aclk_g2d_400_user", + mout_aclk_g2d_400_user_p, MUX_SEL_G2D0, 0, 1), +}; + +static struct samsung_div_clock g2d_div_clks[] __initdata = { + /* DIV_G2D */ + DIV(CLK_DIV_PCLK_G2D, "div_pclk_g2d", "mout_aclk_g2d_266_user", + DIV_G2D, 0, 2), +}; + +static struct samsung_gate_clock g2d_gate_clks[] __initdata = { + /* DIV_ENABLE_ACLK_G2D */ + GATE(CLK_ACLK_SMMU_MDMA1, "aclk_smmu_mdma1", "mout_aclk_g2d_266_user", + DIV_ENABLE_ACLK_G2D, 12, 0, 0), + GATE(CLK_ACLK_BTS_MDMA1, "aclk_bts_mdam1", "mout_aclk_g2d_266_user", + DIV_ENABLE_ACLK_G2D, 11, 0, 0), + GATE(CLK_ACLK_BTS_G2D, "aclk_bts_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 10, 0, 0), + GATE(CLK_ACLK_ALB_G2D, "aclk_alb_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 9, 0, 0), + GATE(CLK_ACLK_AXIUS_G2DX, "aclk_axius_g2dx", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 8, 0, 0), + GATE(CLK_ACLK_ASYNCAXI_SYSX, "aclk_asyncaxi_sysx", + "mout_aclk_g2d_400_user", DIV_ENABLE_ACLK_G2D, + 7, 0, 0), + GATE(CLK_ACLK_AHB2APB_G2D1P, "aclk_ahb2apb_g2d1p", "div_pclk_g2d", + DIV_ENABLE_ACLK_G2D, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_G2D0P, "aclk_ahb2apb_g2d0p", "div_pclk_g2d", + DIV_ENABLE_ACLK_G2D, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_G2DX, "aclk_xiu_g2dx", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2DNP_133, "aclk_g2dnp_133", "div_pclk_g2d", + DIV_ENABLE_ACLK_G2D, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2DND_400, "aclk_g2dnd_400", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MDMA1, "aclk_mdma1", "mout_aclk_g2d_266_user", + DIV_ENABLE_ACLK_G2D, 1, 0, 0), + GATE(CLK_ACLK_G2D, "aclk_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 0, 0, 0), + + /* DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D */ + GATE(CLK_ACLK_SMMU_G2D, "aclk_smmu_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D, 0, 0, 0), + + /* DIV_ENABLE_PCLK_G2D */ + GATE(CLK_PCLK_SMMU_MDMA1, "pclk_smmu_mdma1", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 7, 0, 0), + GATE(CLK_PCLK_BTS_MDMA1, "pclk_bts_mdam1", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 6, 0, 0), + GATE(CLK_PCLK_BTS_G2D, "pclk_bts_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 5, 0, 0), + GATE(CLK_PCLK_ALB_G2D, "pclk_alb_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 4, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_SYSX, "pclk_asyncaxi_sysx", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 3, 0, 0), + GATE(CLK_PCLK_PMU_G2D, "pclk_pmu_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_G2D, "pclk_sysreg_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_G2D, "pclk_g2d", "div_pclk_g2d", DIV_ENABLE_PCLK_G2D, + 0, 0, 0), + + /* DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D */ + GATE(CLK_PCLK_SMMU_G2D, "pclk_smmu_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D, 0, 0, 0), +}; + +static struct samsung_cmu_info g2d_cmu_info __initdata = { + .mux_clks = g2d_mux_clks, + .nr_mux_clks = ARRAY_SIZE(g2d_mux_clks), + .div_clks = g2d_div_clks, + .nr_div_clks = ARRAY_SIZE(g2d_div_clks), + .gate_clks = g2d_gate_clks, + .nr_gate_clks = ARRAY_SIZE(g2d_gate_clks), + .nr_clk_ids = G2D_NR_CLK, + .clk_regs = g2d_clk_regs, + .nr_clk_regs = ARRAY_SIZE(g2d_clk_regs), +}; + +static void __init exynos5433_cmu_g2d_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &g2d_cmu_info); +} + +CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d", + exynos5433_cmu_g2d_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 5b3397d9843a..818d6b6bbdc4 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -100,6 +100,12 @@ #define CLK_DIV_SCLK_PCM1 128 #define CLK_DIV_SCLK_AUDIO1 129 #define CLK_DIV_SCLK_AUDIO0 130 +#define CLK_DIV_ACLK_GSCL_111 131 +#define CLK_DIV_ACLK_GSCL_333 132 +#define CLK_DIV_ACLK_HEVC_400 133 +#define CLK_DIV_ACLK_MFC_400 134 +#define CLK_DIV_ACLK_G2D_266 135 +#define CLK_DIV_ACLK_G2D_400 136 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -121,8 +127,10 @@ #define CLK_SCLK_SLIMBUS 217 #define CLK_SCLK_AUDIO1 218 #define CLK_SCLK_AUDIO0 219 +#define CLK_ACLK_G2D_266 220 +#define CLK_ACLK_G2D_400 221 -#define TOP_NR_CLK 220 +#define TOP_NR_CLK 222 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -286,4 +294,36 @@ #define FSYS_NR_CLK 66 +/* CMU_G2D */ +#define CLK_MUX_ACLK_G2D_266_USER 1 +#define CLK_MUX_ACLK_G2D_400_USER 2 + +#define CLK_DIV_PCLK_G2D 3 + +#define CLK_ACLK_SMMU_MDMA1 4 +#define CLK_ACLK_BTS_MDMA1 5 +#define CLK_ACLK_BTS_G2D 6 +#define CLK_ACLK_ALB_G2D 7 +#define CLK_ACLK_AXIUS_G2DX 8 +#define CLK_ACLK_ASYNCAXI_SYSX 9 +#define CLK_ACLK_AHB2APB_G2D1P 10 +#define CLK_ACLK_AHB2APB_G2D0P 11 +#define CLK_ACLK_XIU_G2DX 12 +#define CLK_ACLK_G2DNP_133 13 +#define CLK_ACLK_G2DND_400 14 +#define CLK_ACLK_MDMA1 15 +#define CLK_ACLK_G2D 16 +#define CLK_ACLK_SMMU_G2D 17 +#define CLK_PCLK_SMMU_MDMA1 18 +#define CLK_PCLK_BTS_MDMA1 19 +#define CLK_PCLK_BTS_G2D 20 +#define CLK_PCLK_ALB_G2D 21 +#define CLK_PCLK_ASYNCAXI_SYSX 22 +#define CLK_PCLK_PMU_G2D 23 +#define CLK_PCLK_SYSREG_G2D 24 +#define CLK_PCLK_G2D 25 +#define CLK_PCLK_SMMU_G2D 26 + +#define G2D_NR_CLK 27 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 06d2f9dfa663367e8cc1690d7e5ce4113e5dbcc1 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:01 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_MIF domain This patch adds the mux/divider/gate clocks of CMU_MIF domain which includes the clocks for DMC(DRAM memory controller) and CCI(Cache Coherent Interconnect). The CMU_MIF domain provides the source clocks for CMU_DISP/CMU_BUS2. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 599 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 190 ++++++++++- 2 files changed, 788 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 24218dba8218..09ccf11bab64 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -740,6 +740,66 @@ CLK_OF_DECLARE(exynos5433_cmu_cpif, "samsung,exynos5433-cmu-cpif", #define MFC_PLL_CON0 0x0130 #define MFC_PLL_CON1 0x0134 #define MFC_PLL_FREQ_DET 0x013c +#define MUX_SEL_MIF0 0x0200 +#define MUX_SEL_MIF1 0x0204 +#define MUX_SEL_MIF2 0x0208 +#define MUX_SEL_MIF3 0x020c +#define MUX_SEL_MIF4 0x0210 +#define MUX_SEL_MIF5 0x0214 +#define MUX_SEL_MIF6 0x0218 +#define MUX_SEL_MIF7 0x021c +#define MUX_ENABLE_MIF0 0x0300 +#define MUX_ENABLE_MIF1 0x0304 +#define MUX_ENABLE_MIF2 0x0308 +#define MUX_ENABLE_MIF3 0x030c +#define MUX_ENABLE_MIF4 0x0310 +#define MUX_ENABLE_MIF5 0x0314 +#define MUX_ENABLE_MIF6 0x0318 +#define MUX_ENABLE_MIF7 0x031c +#define MUX_STAT_MIF0 0x0400 +#define MUX_STAT_MIF1 0x0404 +#define MUX_STAT_MIF2 0x0408 +#define MUX_STAT_MIF3 0x040c +#define MUX_STAT_MIF4 0x0410 +#define MUX_STAT_MIF5 0x0414 +#define MUX_STAT_MIF6 0x0418 +#define MUX_STAT_MIF7 0x041c +#define DIV_MIF1 0x0604 +#define DIV_MIF2 0x0608 +#define DIV_MIF3 0x060c +#define DIV_MIF4 0x0610 +#define DIV_MIF5 0x0614 +#define DIV_MIF_PLL_FREQ_DET 0x0618 +#define DIV_STAT_MIF1 0x0704 +#define DIV_STAT_MIF2 0x0708 +#define DIV_STAT_MIF3 0x070c +#define DIV_STAT_MIF4 0x0710 +#define DIV_STAT_MIF5 0x0714 +#define DIV_STAT_MIF_PLL_FREQ_DET 0x0718 +#define ENABLE_ACLK_MIF0 0x0800 +#define ENABLE_ACLK_MIF1 0x0804 +#define ENABLE_ACLK_MIF2 0x0808 +#define ENABLE_ACLK_MIF3 0x080c +#define ENABLE_PCLK_MIF 0x0900 +#define ENABLE_PCLK_MIF_SECURE_DREX0_TZ 0x0904 +#define ENABLE_PCLK_MIF_SECURE_DREX1_TZ 0x0908 +#define ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT 0x090c +#define ENABLE_PCLK_MIF_SECURE_RTC 0x0910 +#define ENABLE_SCLK_MIF 0x0a00 +#define ENABLE_IP_MIF0 0x0b00 +#define ENABLE_IP_MIF1 0x0b04 +#define ENABLE_IP_MIF2 0x0b08 +#define ENABLE_IP_MIF3 0x0b0c +#define ENABLE_IP_MIF_SECURE_DREX0_TZ 0x0b10 +#define ENABLE_IP_MIF_SECURE_DREX1_TZ 0x0b14 +#define ENABLE_IP_MIF_SECURE_MONOTONIC_CNT 0x0b18 +#define ENABLE_IP_MIF_SECURE_RTC 0x0b1c +#define CLKOUT_CMU_MIF 0x0c00 +#define CLKOUT_CMU_MIF_DIV_STAT 0x0c04 +#define DREX_FREQ_CTRL0 0x1000 +#define DREX_FREQ_CTRL1 0x1004 +#define PAUSE 0x1008 +#define DDRPHY_LOCK_CTRL 0x100c static unsigned long mif_clk_regs[] __initdata = { MEM0_PLL_LOCK, @@ -758,6 +818,66 @@ static unsigned long mif_clk_regs[] __initdata = { MFC_PLL_CON0, MFC_PLL_CON1, MFC_PLL_FREQ_DET, + MUX_SEL_MIF0, + MUX_SEL_MIF1, + MUX_SEL_MIF2, + MUX_SEL_MIF3, + MUX_SEL_MIF4, + MUX_SEL_MIF5, + MUX_SEL_MIF6, + MUX_SEL_MIF7, + MUX_ENABLE_MIF0, + MUX_ENABLE_MIF1, + MUX_ENABLE_MIF2, + MUX_ENABLE_MIF3, + MUX_ENABLE_MIF4, + MUX_ENABLE_MIF5, + MUX_ENABLE_MIF6, + MUX_ENABLE_MIF7, + MUX_STAT_MIF0, + MUX_STAT_MIF1, + MUX_STAT_MIF2, + MUX_STAT_MIF3, + MUX_STAT_MIF4, + MUX_STAT_MIF5, + MUX_STAT_MIF6, + MUX_STAT_MIF7, + DIV_MIF1, + DIV_MIF2, + DIV_MIF3, + DIV_MIF4, + DIV_MIF5, + DIV_MIF_PLL_FREQ_DET, + DIV_STAT_MIF1, + DIV_STAT_MIF2, + DIV_STAT_MIF3, + DIV_STAT_MIF4, + DIV_STAT_MIF5, + DIV_STAT_MIF_PLL_FREQ_DET, + ENABLE_ACLK_MIF0, + ENABLE_ACLK_MIF1, + ENABLE_ACLK_MIF2, + ENABLE_ACLK_MIF3, + ENABLE_PCLK_MIF, + ENABLE_PCLK_MIF_SECURE_DREX0_TZ, + ENABLE_PCLK_MIF_SECURE_DREX1_TZ, + ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT, + ENABLE_PCLK_MIF_SECURE_RTC, + ENABLE_SCLK_MIF, + ENABLE_IP_MIF0, + ENABLE_IP_MIF1, + ENABLE_IP_MIF2, + ENABLE_IP_MIF3, + ENABLE_IP_MIF_SECURE_DREX0_TZ, + ENABLE_IP_MIF_SECURE_DREX1_TZ, + ENABLE_IP_MIF_SECURE_MONOTONIC_CNT, + ENABLE_IP_MIF_SECURE_RTC, + CLKOUT_CMU_MIF, + CLKOUT_CMU_MIF_DIV_STAT, + DREX_FREQ_CTRL0, + DREX_FREQ_CTRL1, + PAUSE, + DDRPHY_LOCK_CTRL, }; static struct samsung_pll_clock mif_pll_clks[] __initdata = { @@ -771,9 +891,488 @@ static struct samsung_pll_clock mif_pll_clks[] __initdata = { MFC_PLL_LOCK, MFC_PLL_CON0, exynos5443_pll_rates), }; +/* list of all parent clock list */ +PNAME(mout_mfc_pll_div2_p) = { "mout_mfc_pll", "dout_mfc_pll", }; +PNAME(mout_bus_pll_div2_p) = { "mout_bus_pll", "dout_bus_pll", }; +PNAME(mout_mem1_pll_div2_p) = { "mout_mem1_pll", "dout_mem1_pll", }; +PNAME(mout_mem0_pll_div2_p) = { "mout_mem0_pll", "dout_mem0_pll", }; +PNAME(mout_mfc_pll_p) = { "oscclk", "fout_mfc_pll", }; +PNAME(mout_bus_pll_p) = { "oscclk", "fout_bus_pll", }; +PNAME(mout_mem1_pll_p) = { "oscclk", "fout_mem1_pll", }; +PNAME(mout_mem0_pll_p) = { "oscclk", "fout_mem0_pll", }; + +PNAME(mout_clk2x_phy_c_p) = { "mout_mem0_pll_div2", "mout_clkm_phy_b", }; +PNAME(mout_clk2x_phy_b_p) = { "mout_bus_pll_div2", "mout_clkm_phy_a", }; +PNAME(mout_clk2x_phy_a_p) = { "mout_bus_pll_div2", "mout_mfc_pll_div2", }; +PNAME(mout_clkm_phy_b_p) = { "mout_mem1_pll_div2", "mout_clkm_phy_a", }; + +PNAME(mout_aclk_mifnm_200_p) = { "mout_mem0_pll_div2", "div_mif_pre", }; +PNAME(mout_aclk_mifnm_400_p) = { "mout_mem1_pll_div2", "mout_bus_pll_div2",}; + +PNAME(mout_aclk_disp_333_b_p) = { "mout_aclk_disp_333_a", + "mout_bus_pll_div2", }; +PNAME(mout_aclk_disp_333_a_p) = { "mout_mfc_pll_div2", "sclk_mphy_pll", }; + +PNAME(mout_sclk_decon_vclk_c_p) = { "mout_sclk_decon_vclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_vclk_b_p) = { "mout_sclk_decon_vclk_a", + "mout_mfc_pll_div2", }; +PNAME(mout_sclk_decon_p) = { "oscclk", "mout_bus_pll_div2", }; +PNAME(mout_sclk_decon_eclk_c_p) = { "mout_sclk_decon_eclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_eclk_b_p) = { "mout_sclk_decon_eclk_a", + "mout_mfc_pll_div2", }; + +PNAME(mout_sclk_decon_tv_eclk_c_p) = { "mout_sclk_decon_tv_eclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_tv_eclk_b_p) = { "mout_sclk_decon_tv_eclk_a", + "mout_mfc_pll_div2", }; +PNAME(mout_sclk_dsd_c_p) = { "mout_sclk_dsd_b", "mout_bus_pll_div2", }; +PNAME(mout_sclk_dsd_b_p) = { "mout_sclk_dsd_a", "sclk_mphy_pll", }; +PNAME(mout_sclk_dsd_a_p) = { "oscclk", "mout_mfc_pll_div2", }; + +PNAME(mout_sclk_dsim0_c_p) = { "mout_sclk_dsim0_b", "sclk_mphy_pll", }; +PNAME(mout_sclk_dsim0_b_p) = { "mout_sclk_dsim0_a", "mout_mfc_pll_div2" }; + +PNAME(mout_sclk_decon_tv_vclk_c_p) = { "mout_sclk_decon_tv_vclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_tv_vclk_b_p) = { "mout_sclk_decon_tv_vclk_a", + "mout_mfc_pll_div2", }; +PNAME(mout_sclk_dsim1_c_p) = { "mout_sclk_dsim1_b", "sclk_mphy_pll", }; +PNAME(mout_sclk_dsim1_b_p) = { "mout_sclk_dsim1_a", "mout_mfc_pll_div2",}; + +static struct samsung_fixed_factor_clock mif_fixed_factor_clks[] __initdata = { + /* dout_{mfc|bus|mem1|mem0}_pll is half fixed rate from parent mux */ + FFACTOR(CLK_DOUT_MFC_PLL, "dout_mfc_pll", "mout_mfc_pll", 1, 1, 0), + FFACTOR(CLK_DOUT_BUS_PLL, "dout_bus_pll", "mout_bus_pll", 1, 1, 0), + FFACTOR(CLK_DOUT_MEM1_PLL, "dout_mem1_pll", "mout_mem1_pll", 1, 1, 0), + FFACTOR(CLK_DOUT_MEM0_PLL, "dout_mem0_pll", "mout_mem0_pll", 1, 1, 0), +}; + +static struct samsung_mux_clock mif_mux_clks[] __initdata = { + /* MUX_SEL_MIF0 */ + MUX(CLK_MOUT_MFC_PLL_DIV2, "mout_mfc_pll_div2", mout_mfc_pll_div2_p, + MUX_SEL_MIF0, 28, 1), + MUX(CLK_MOUT_BUS_PLL_DIV2, "mout_bus_pll_div2", mout_bus_pll_div2_p, + MUX_SEL_MIF0, 24, 1), + MUX(CLK_MOUT_MEM1_PLL_DIV2, "mout_mem1_pll_div2", mout_mem1_pll_div2_p, + MUX_SEL_MIF0, 20, 1), + MUX(CLK_MOUT_MEM0_PLL_DIV2, "mout_mem0_pll_div2", mout_mem0_pll_div2_p, + MUX_SEL_MIF0, 16, 1), + MUX(CLK_MOUT_MFC_PLL, "mout_mfc_pll", mout_mfc_pll_p, MUX_SEL_MIF0, + 12, 1), + MUX(CLK_MOUT_BUS_PLL, "mout_bus_pll", mout_bus_pll_p, MUX_SEL_MIF0, + 8, 1), + MUX(CLK_MOUT_MEM1_PLL, "mout_mem1_pll", mout_mem1_pll_p, MUX_SEL_MIF0, + 4, 1), + MUX(CLK_MOUT_MEM0_PLL, "mout_mem0_pll", mout_mem0_pll_p, MUX_SEL_MIF0, + 0, 1), + + /* MUX_SEL_MIF1 */ + MUX(CLK_MOUT_CLK2X_PHY_C, "mout_clk2x_phy_c", mout_clk2x_phy_c_p, + MUX_SEL_MIF1, 24, 1), + MUX(CLK_MOUT_CLK2X_PHY_B, "mout_clk2x_phy_b", mout_clk2x_phy_b_p, + MUX_SEL_MIF1, 20, 1), + MUX(CLK_MOUT_CLK2X_PHY_A, "mout_clk2x_phy_a", mout_clk2x_phy_a_p, + MUX_SEL_MIF1, 16, 1), + MUX(CLK_MOUT_CLKM_PHY_C, "mout_clkm_phy_c", mout_clk2x_phy_c_p, + MUX_SEL_MIF1, 12, 1), + MUX(CLK_MOUT_CLKM_PHY_B, "mout_clkm_phy_b", mout_clkm_phy_b_p, + MUX_SEL_MIF1, 8, 1), + MUX(CLK_MOUT_CLKM_PHY_A, "mout_clkm_phy_a", mout_clk2x_phy_a_p, + MUX_SEL_MIF1, 4, 1), + + /* MUX_SEL_MIF2 */ + MUX(CLK_MOUT_ACLK_MIFNM_200, "mout_aclk_mifnm_200", + mout_aclk_mifnm_200_p, MUX_SEL_MIF2, 8, 1), + MUX(CLK_MOUT_ACLK_MIFNM_400, "mout_aclk_mifnm_400", + mout_aclk_mifnm_400_p, MUX_SEL_MIF2, 0, 1), + + /* MUX_SEL_MIF3 */ + MUX(CLK_MOUT_ACLK_DISP_333_B, "mout_aclk_disp_333_b", + mout_aclk_disp_333_b_p, MUX_SEL_MIF3, 4, 1), + MUX(CLK_MOUT_ACLK_DISP_333_A, "mout_aclk_disp_333_a", + mout_aclk_disp_333_a_p, MUX_SEL_MIF3, 0, 1), + + /* MUX_SEL_MIF4 */ + MUX(CLK_MOUT_SCLK_DECON_VCLK_C, "mout_sclk_decon_vclk_c", + mout_sclk_decon_vclk_c_p, MUX_SEL_MIF4, 24, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK_B, "mout_sclk_decon_vclk_b", + mout_sclk_decon_vclk_b_p, MUX_SEL_MIF4, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK_A, "mout_sclk_decon_vclk_a", + mout_sclk_decon_p, MUX_SEL_MIF4, 16, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_C, "mout_sclk_decon_eclk_c", + mout_sclk_decon_eclk_c_p, MUX_SEL_MIF4, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_B, "mout_sclk_decon_eclk_b", + mout_sclk_decon_eclk_b_p, MUX_SEL_MIF4, 4, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_A, "mout_sclk_decon_eclk_a", + mout_sclk_decon_p, MUX_SEL_MIF4, 0, 1), + + /* MUX_SEL_MIF5 */ + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_C, "mout_sclk_decon_tv_eclk_c", + mout_sclk_decon_tv_eclk_c_p, MUX_SEL_MIF5, 24, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_B, "mout_sclk_decon_tv_eclk_b", + mout_sclk_decon_tv_eclk_b_p, MUX_SEL_MIF5, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_A, "mout_sclk_decon_tv_eclk_a", + mout_sclk_decon_p, MUX_SEL_MIF5, 16, 1), + MUX(CLK_MOUT_SCLK_DSD_C, "mout_sclk_dsd_c", mout_sclk_dsd_c_p, + MUX_SEL_MIF5, 8, 1), + MUX(CLK_MOUT_SCLK_DSD_B, "mout_sclk_dsd_b", mout_sclk_dsd_b_p, + MUX_SEL_MIF5, 4, 1), + MUX(CLK_MOUT_SCLK_DSD_A, "mout_sclk_dsd_a", mout_sclk_dsd_a_p, + MUX_SEL_MIF5, 0, 1), + + /* MUX_SEL_MIF6 */ + MUX(CLK_MOUT_SCLK_DSIM0_C, "mout_sclk_dsim0_c", mout_sclk_dsim0_c_p, + MUX_SEL_MIF6, 8, 1), + MUX(CLK_MOUT_SCLK_DSIM0_B, "mout_sclk_dsim0_b", mout_sclk_dsim0_b_p, + MUX_SEL_MIF6, 4, 1), + MUX(CLK_MOUT_SCLK_DSIM0_A, "mout_sclk_dsim0_a", mout_sclk_decon_p, + MUX_SEL_MIF6, 0, 1), + + /* MUX_SEL_MIF7 */ + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_C, "mout_sclk_decon_tv_vclk_c", + mout_sclk_decon_tv_vclk_c_p, MUX_SEL_MIF7, 24, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_B, "mout_sclk_decon_tv_vclk_b", + mout_sclk_decon_tv_vclk_b_p, MUX_SEL_MIF7, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_A, "mout_sclk_decon_tv_vclk_a", + mout_sclk_decon_p, MUX_SEL_MIF7, 16, 1), + MUX(CLK_MOUT_SCLK_DSIM1_C, "mout_sclk_dsim1_c", mout_sclk_dsim1_c_p, + MUX_SEL_MIF7, 8, 1), + MUX(CLK_MOUT_SCLK_DSIM1_B, "mout_sclk_dsim1_b", mout_sclk_dsim1_b_p, + MUX_SEL_MIF7, 4, 1), + MUX(CLK_MOUT_SCLK_DSIM1_A, "mout_sclk_dsim1_a", mout_sclk_decon_p, + MUX_SEL_MIF7, 0, 1), +}; + +static struct samsung_div_clock mif_div_clks[] __initdata = { + /* DIV_MIF1 */ + DIV(CLK_DIV_SCLK_HPM_MIF, "div_sclk_hpm_mif", "div_clk2x_phy", + DIV_MIF1, 16, 2), + DIV(CLK_DIV_ACLK_DREX1, "div_aclk_drex1", "div_clk2x_phy", DIV_MIF1, + 12, 2), + DIV(CLK_DIV_ACLK_DREX0, "div_aclk_drex0", "div_clk2x_phy", DIV_MIF1, + 8, 2), + DIV(CLK_DIV_CLK2XPHY, "div_clk2x_phy", "mout_clk2x_phy_c", DIV_MIF1, + 4, 4), + + /* DIV_MIF2 */ + DIV(CLK_DIV_ACLK_MIF_266, "div_aclk_mif_266", "mout_bus_pll_div2", + DIV_MIF2, 20, 3), + DIV(CLK_DIV_ACLK_MIFND_133, "div_aclk_mifnd_133", "div_mif_pre", + DIV_MIF2, 16, 4), + DIV(CLK_DIV_ACLK_MIF_133, "div_aclk_mif_133", "div_mif_pre", + DIV_MIF2, 12, 4), + DIV(CLK_DIV_ACLK_MIFNM_200, "div_aclk_mifnm_200", + "mout_aclk_mifnm_200", DIV_MIF2, 8, 3), + DIV(CLK_DIV_ACLK_MIF_200, "div_aclk_mif_200", "div_aclk_mif_400", + DIV_MIF2, 4, 2), + DIV(CLK_DIV_ACLK_MIF_400, "div_aclk_mif_400", "mout_aclk_mifnm_400", + DIV_MIF2, 0, 3), + + /* DIV_MIF3 */ + DIV(CLK_DIV_ACLK_BUS2_400, "div_aclk_bus2_400", "div_mif_pre", + DIV_MIF3, 16, 4), + DIV(CLK_DIV_ACLK_DISP_333, "div_aclk_disp_333", "mout_aclk_disp_333_b", + DIV_MIF3, 4, 3), + DIV(CLK_DIV_ACLK_CPIF_200, "div_aclk_cpif_200", "mout_aclk_mifnm_200", + DIV_MIF3, 0, 3), + + /* DIV_MIF4 */ + DIV(CLK_DIV_SCLK_DSIM1, "div_sclk_dsim1", "mout_sclk_dsim1_c", + DIV_MIF4, 24, 4), + DIV(CLK_DIV_SCLK_DECON_TV_VCLK, "div_sclk_decon_tv_vclk", + "mout_sclk_decon_tv_vclk_c", DIV_MIF4, 20, 4), + DIV(CLK_DIV_SCLK_DSIM0, "div_sclk_dsim0", "mout_sclk_dsim0_c", + DIV_MIF4, 16, 4), + DIV(CLK_DIV_SCLK_DSD, "div_sclk_dsd", "mout_sclk_dsd_c", + DIV_MIF4, 12, 4), + DIV(CLK_DIV_SCLK_DECON_TV_ECLK, "div_sclk_decon_tv_eclk", + "mout_sclk_decon_tv_eclk_c", DIV_MIF4, 8, 4), + DIV(CLK_DIV_SCLK_DECON_VCLK, "div_sclk_decon_vclk", + "mout_sclk_decon_vclk_c", DIV_MIF4, 4, 4), + DIV(CLK_DIV_SCLK_DECON_ECLK, "div_sclk_decon_eclk", + "mout_sclk_decon_eclk_c", DIV_MIF4, 0, 4), + + /* DIV_MIF5 */ + DIV(CLK_DIV_MIF_PRE, "div_mif_pre", "mout_bus_pll_div2", DIV_MIF5, + 0, 3), +}; + +static struct samsung_gate_clock mif_gate_clks[] __initdata = { + /* ENABLE_ACLK_MIF0 */ + GATE(CLK_CLK2X_PHY1, "clk2k_phy1", "div_clk2x_phy", ENABLE_ACLK_MIF0, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CLK2X_PHY0, "clk2x_phy0", "div_clk2x_phy", ENABLE_ACLK_MIF0, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CLKM_PHY1, "clkm_phy1", "mout_clkm_phy_c", ENABLE_ACLK_MIF0, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CLKM_PHY0, "clkm_phy0", "mout_clkm_phy_c", ENABLE_ACLK_MIF0, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_RCLK_DREX1, "rclk_drex1", "oscclk", ENABLE_ACLK_MIF0, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_RCLK_DREX0, "rclk_drex0", "oscclk", ENABLE_ACLK_MIF0, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_TZ, "aclk_drex1_tz", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_TZ, "aclk_drex0_tz", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_PEREV, "aclk_drex1_perev", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_PEREV, "aclk_drex0_perev", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_MEMIF, "aclk_drex1_memif", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_MEMIF, "aclk_drex0_memif", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_SCH, "aclk_drex1_sch", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_SCH, "aclk_drex0_sch", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_BUSIF, "aclk_drex1_busif", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_BUSIF, "aclk_drex0_busif", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_BUSIF_RD, "aclk_drex1_busif_rd", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_BUSIF_RD, "aclk_drex0_busif_rd", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1, "aclk_drex1", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0, "aclk_drex0", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 1, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MIF1 */ + GATE(CLK_ACLK_ASYNCAXIS_MIF_IMEM, "aclk_asyncaxis_mif_imem", + "div_aclk_mif_200", ENABLE_ACLK_MIF1, 28, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_NOC_P_CCI, "aclk_asyncaxis_noc_p_cci", + "div_aclk_mif_200", ENABLE_ACLK_MIF1, + 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_NOC_P_CCI, "aclk_asyncaxim_noc_p_cci", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CP1, "aclk_asyncaxis_cp1", + "div_aclk_mifnm_200", ENABLE_ACLK_MIF1, + 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_CP1, "aclk_asyncaxim_cp1", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CP0, "aclk_asyncaxis_cp0", + "div_aclk_mifnm_200", ENABLE_ACLK_MIF1, + 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_CP0, "aclk_asyncaxim_cp0", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX1_3, "aclk_asyncaxis_drex1_3", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX1_3, "aclk_asyncaxim_drex1_3", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX1_1, "aclk_asyncaxis_drex1_1", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX1_1, "aclk_asyncaxim_drex1_1", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX1_0, "aclk_asyncaxis_drex1_0", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX1_0, "aclk_asyncaxim_drex1_0", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX0_3, "aclk_asyncaxis_drex0_3", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX0_3, "aclk_asyncaxim_drex0_3", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX0_1, "aclk_asyncaxis_drex0_1", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX0_1, "aclk_asyncaxim_drex0_1", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX0_0, "aclk_asyncaxis_drex0_0", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX0_0, "aclk_asyncaxim_drex0_0", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_MIF2P, "aclk_ahb2apb_mif2p", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_MIF1P, "aclk_ahb2apb_mif1p", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_MIF0P, "aclk_ahb2apb_mif0p", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_IXIU_CCI, "aclk_ixiu_cci", "div_aclk_mif_400", + ENABLE_ACLK_MIF1, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_MIFSFRX, "aclk_xiu_mifsfrx", "div_aclk_mif_200", + ENABLE_ACLK_MIF1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFNP_133, "aclk_mifnp_133", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFNM_200, "aclk_mifnm_200", "div_aclk_mifnm_200", + ENABLE_ACLK_MIF1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFND_133, "aclk_mifnd_133", "div_aclk_mifnd_133", + ENABLE_ACLK_MIF1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFND_400, "aclk_mifnd_400", "div_aclk_mif_400", + ENABLE_ACLK_MIF1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CCI, "aclk_cci", "div_aclk_mif_400", ENABLE_ACLK_MIF1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MIF2 */ + GATE(CLK_ACLK_MIFND_266, "aclk_mifnd_266", "div_aclk_mif_266", + ENABLE_ACLK_MIF2, 20, 0, 0), + GATE(CLK_ACLK_PPMU_DREX1S3, "aclk_ppmu_drex1s3", "div_aclk_drex1", + ENABLE_ACLK_MIF2, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX1S1, "aclk_ppmu_drex1s1", "div_aclk_drex1", + ENABLE_ACLK_MIF2, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX1S0, "aclk_ppmu_drex1s0", "div_aclk_drex1", + ENABLE_ACLK_MIF2, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX0S3, "aclk_ppmu_drex0s3", "div_aclk_drex0", + ENABLE_ACLK_MIF2, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX0S1, "aclk_ppmu_drex0s1", "div_aclk_drex0", + ENABLE_ACLK_MIF2, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX0S0, "aclk_ppmu_drex0s0", "div_aclk_drex0", + ENABLE_ACLK_MIF2, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIDS_CCI_MIFSFRX, "aclk_axids_cci_mifsfrx", + "div_aclk_mif_200", ENABLE_ACLK_MIF2, 7, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXISYNCDNS_CCI, "aclk_axisyncdns_cci", + "div_aclk_mif_400", ENABLE_ACLK_MIF2, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXISYNCDN_CCI, "aclk_axisyncdn_cci", "div_aclk_mif_400", + ENABLE_ACLK_MIF2, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXISYNCDN_NOC_D, "aclk_axisyncdn_noc_d", + "div_aclk_mif_200", ENABLE_ACLK_MIF2, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_MIF_CSSYS, "aclk_asyncapbs_mif_cssys", + "div_aclk_mifnd_133", ENABLE_ACLK_MIF2, 0, 0, 0), + + /* ENABLE_ACLK_MIF3 */ + GATE(CLK_ACLK_BUS2_400, "aclk_bus2_400", "div_aclk_bus2_400", + ENABLE_ACLK_MIF3, 4, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_DISP_333, "aclk_disp_333", "div_aclk_disp_333", + ENABLE_ACLK_MIF3, 1, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_CPIF_200, "aclk_cpif_200", "div_aclk_cpif_200", + ENABLE_ACLK_MIF3, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + + /* ENABLE_PCLK_MIF */ + GATE(CLK_PCLK_PPMU_DREX1S3, "pclk_ppmu_drex1s3", "div_aclk_drex1", + ENABLE_PCLK_MIF, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX1S1, "pclk_ppmu_drex1s1", "div_aclk_drex1", + ENABLE_PCLK_MIF, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX1S0, "pclk_ppmu_drex1s0", "div_aclk_drex1", + ENABLE_PCLK_MIF, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX0S3, "pclk_ppmu_drex0s3", "div_aclk_drex0", + ENABLE_PCLK_MIF, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX0S1, "pclk_ppmu_drex0s1", "div_aclk_drex0", + ENABLE_PCLK_MIF, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX0S0, "pclk_ppmu_drex0s0", "div_aclk_drex0", + ENABLE_PCLK_MIF, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_NOC_P_CCI, "pclk_asyncaxi_noc_p_cci", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 21, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_CP1, "pclk_asyncaxi_cp1", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 19, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_CP0, "pclk_asyncaxi_cp0", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 18, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX1_3, "pclk_asyncaxi_drex1_3", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 17, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX1_1, "pclk_asyncaxi_drex1_1", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 16, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX1_0, "pclk_asyncaxi_drex1_0", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 15, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX0_3, "pclk_asyncaxi_drex0_3", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 14, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX0_1, "pclk_asyncaxi_drex0_1", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 13, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX0_0, "pclk_asyncaxi_drex0_0", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 12, 0, 0), + GATE(CLK_PCLK_MIFSRVND_133, "pclk_mifsrvnd_133", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 11, 0, 0), + GATE(CLK_PCLK_PMU_MIF, "pclk_pmu_mif", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_MIF, "pclk_sysreg_mif", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_ALIVE, "pclk_gpio_alive", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ABB, "pclk_abb", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 7, 0, 0), + GATE(CLK_PCLK_PMU_APBIF, "pclk_pmu_apbif", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DDR_PHY1, "pclk_ddr_phy1", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 5, 0, 0), + GATE(CLK_PCLK_DREX1, "pclk_drex1", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DDR_PHY0, "pclk_ddr_phy0", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 2, 0, 0), + GATE(CLK_PCLK_DREX0, "pclk_drex0", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MIF_SECURE_DREX0_TZ */ + GATE(CLK_PCLK_DREX0_TZ, "pclk_drex0_tz", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_DREX0_TZ, 0, 0, 0), + + /* ENABLE_PCLK_MIF_SECURE_DREX1_TZ */ + GATE(CLK_PCLK_DREX1_TZ, "pclk_drex1_tz", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_DREX1_TZ, 0, 0, 0), + + /* ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT */ + GATE(CLK_PCLK_MONOTONIC_CNT, "pclk_monotonic_cnt", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_RTC, 0, 0, 0), + + /* ENABLE_PCLK_MIF_SECURE_RTC */ + GATE(CLK_PCLK_RTC, "pclk_rtc", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_RTC, 0, 0, 0), + + /* ENABLE_SCLK_MIF */ + GATE(CLK_SCLK_DSIM1_DISP, "sclk_dsim1_disp", "div_sclk_dsim1", + ENABLE_SCLK_MIF, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_TV_VCLK_DISP, "sclk_decon_tv_vclk_disp", + "div_sclk_decon_tv_vclk", ENABLE_SCLK_MIF, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DSIM0_DISP, "sclk_dsim0_disp", "div_sclk_dsim0", + ENABLE_SCLK_MIF, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DSD_DISP, "sclk_dsd_disp", "div_sclk_dsd", + ENABLE_SCLK_MIF, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_TV_ECLK_DISP, "sclk_decon_tv_eclk_disp", + "div_sclk_decon_tv_eclk", ENABLE_SCLK_MIF, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_VCLK_DISP, "sclk_decon_vclk_disp", + "div_sclk_decon_vclk", ENABLE_SCLK_MIF, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_ECLK_DISP, "sclk_decon_eclk_disp", + "div_sclk_decon_eclk", ENABLE_SCLK_MIF, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_HPM_MIF, "sclk_hpm_mif", "div_sclk_hpm_mif", + ENABLE_SCLK_MIF, 4, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_MFC_PLL, "sclk_mfc_pll", "mout_mfc_pll_div2", + ENABLE_SCLK_MIF, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_BUS_PLL, "sclk_bus_pll", "mout_bus_pll_div2", + ENABLE_SCLK_MIF, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_BUS_PLL_APOLLO, "sclk_bus_pll_apollo", "sclk_bus_pll", + ENABLE_SCLK_MIF, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_BUS_PLL_ATLAS, "sclk_bus_pll_atlas", "sclk_bus_pll", + ENABLE_SCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), +}; + static struct samsung_cmu_info mif_cmu_info __initdata = { .pll_clks = mif_pll_clks, .nr_pll_clks = ARRAY_SIZE(mif_pll_clks), + .mux_clks = mif_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mif_mux_clks), + .div_clks = mif_div_clks, + .nr_div_clks = ARRAY_SIZE(mif_div_clks), + .gate_clks = mif_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mif_gate_clks), + .fixed_factor_clks = mif_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(mif_fixed_factor_clks), .nr_clk_ids = MIF_NR_CLK, .clk_regs = mif_clk_regs, .nr_clk_regs = ARRAY_SIZE(mif_clk_regs), diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 818d6b6bbdc4..6a3ce113e1e5 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -149,8 +149,196 @@ #define CLK_FOUT_MEM1_PLL 2 #define CLK_FOUT_BUS_PLL 3 #define CLK_FOUT_MFC_PLL 4 +#define CLK_DOUT_MFC_PLL 5 +#define CLK_DOUT_BUS_PLL 6 +#define CLK_DOUT_MEM1_PLL 7 +#define CLK_DOUT_MEM0_PLL 8 -#define MIF_NR_CLK 5 +#define CLK_MOUT_MFC_PLL_DIV2 10 +#define CLK_MOUT_BUS_PLL_DIV2 11 +#define CLK_MOUT_MEM1_PLL_DIV2 12 +#define CLK_MOUT_MEM0_PLL_DIV2 13 +#define CLK_MOUT_MFC_PLL 14 +#define CLK_MOUT_BUS_PLL 15 +#define CLK_MOUT_MEM1_PLL 16 +#define CLK_MOUT_MEM0_PLL 17 +#define CLK_MOUT_CLK2X_PHY_C 18 +#define CLK_MOUT_CLK2X_PHY_B 19 +#define CLK_MOUT_CLK2X_PHY_A 20 +#define CLK_MOUT_CLKM_PHY_C 21 +#define CLK_MOUT_CLKM_PHY_B 22 +#define CLK_MOUT_CLKM_PHY_A 23 +#define CLK_MOUT_ACLK_MIFNM_200 24 +#define CLK_MOUT_ACLK_MIFNM_400 25 +#define CLK_MOUT_ACLK_DISP_333_B 26 +#define CLK_MOUT_ACLK_DISP_333_A 27 +#define CLK_MOUT_SCLK_DECON_VCLK_C 28 +#define CLK_MOUT_SCLK_DECON_VCLK_B 29 +#define CLK_MOUT_SCLK_DECON_VCLK_A 30 +#define CLK_MOUT_SCLK_DECON_ECLK_C 31 +#define CLK_MOUT_SCLK_DECON_ECLK_B 32 +#define CLK_MOUT_SCLK_DECON_ECLK_A 33 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_C 34 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_B 35 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_A 36 +#define CLK_MOUT_SCLK_DSD_C 37 +#define CLK_MOUT_SCLK_DSD_B 38 +#define CLK_MOUT_SCLK_DSD_A 39 +#define CLK_MOUT_SCLK_DSIM0_C 40 +#define CLK_MOUT_SCLK_DSIM0_B 41 +#define CLK_MOUT_SCLK_DSIM0_A 42 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_C 46 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_B 47 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_A 48 +#define CLK_MOUT_SCLK_DSIM1_C 49 +#define CLK_MOUT_SCLK_DSIM1_B 50 +#define CLK_MOUT_SCLK_DSIM1_A 51 + +#define CLK_DIV_SCLK_HPM_MIF 55 +#define CLK_DIV_ACLK_DREX1 56 +#define CLK_DIV_ACLK_DREX0 57 +#define CLK_DIV_CLK2XPHY 58 +#define CLK_DIV_ACLK_MIF_266 59 +#define CLK_DIV_ACLK_MIFND_133 60 +#define CLK_DIV_ACLK_MIF_133 61 +#define CLK_DIV_ACLK_MIFNM_200 62 +#define CLK_DIV_ACLK_MIF_200 63 +#define CLK_DIV_ACLK_MIF_400 64 +#define CLK_DIV_ACLK_BUS2_400 65 +#define CLK_DIV_ACLK_DISP_333 66 +#define CLK_DIV_ACLK_CPIF_200 67 +#define CLK_DIV_SCLK_DSIM1 68 +#define CLK_DIV_SCLK_DECON_TV_VCLK 69 +#define CLK_DIV_SCLK_DSIM0 70 +#define CLK_DIV_SCLK_DSD 71 +#define CLK_DIV_SCLK_DECON_TV_ECLK 72 +#define CLK_DIV_SCLK_DECON_VCLK 73 +#define CLK_DIV_SCLK_DECON_ECLK 74 +#define CLK_DIV_MIF_PRE 75 + +#define CLK_CLK2X_PHY1 80 +#define CLK_CLK2X_PHY0 81 +#define CLK_CLKM_PHY1 82 +#define CLK_CLKM_PHY0 83 +#define CLK_RCLK_DREX1 84 +#define CLK_RCLK_DREX0 85 +#define CLK_ACLK_DREX1_TZ 86 +#define CLK_ACLK_DREX0_TZ 87 +#define CLK_ACLK_DREX1_PEREV 88 +#define CLK_ACLK_DREX0_PEREV 89 +#define CLK_ACLK_DREX1_MEMIF 90 +#define CLK_ACLK_DREX0_MEMIF 91 +#define CLK_ACLK_DREX1_SCH 92 +#define CLK_ACLK_DREX0_SCH 93 +#define CLK_ACLK_DREX1_BUSIF 94 +#define CLK_ACLK_DREX0_BUSIF 95 +#define CLK_ACLK_DREX1_BUSIF_RD 96 +#define CLK_ACLK_DREX0_BUSIF_RD 97 +#define CLK_ACLK_DREX1 98 +#define CLK_ACLK_DREX0 99 +#define CLK_ACLK_ASYNCAXIM_ATLAS_CCIX 100 +#define CLK_ACLK_ASYNCAXIS_ATLAS_MIF 101 +#define CLK_ACLK_ASYNCAXIM_ATLAS_MIF 102 +#define CLK_ACLK_ASYNCAXIS_MIF_IMEM 103 +#define CLK_ACLK_ASYNCAXIS_NOC_P_CCI 104 +#define CLK_ACLK_ASYNCAXIM_NOC_P_CCI 105 +#define CLK_ACLK_ASYNCAXIS_CP1 106 +#define CLK_ACLK_ASYNCAXIM_CP1 107 +#define CLK_ACLK_ASYNCAXIS_CP0 108 +#define CLK_ACLK_ASYNCAXIM_CP0 109 +#define CLK_ACLK_ASYNCAXIS_DREX1_3 110 +#define CLK_ACLK_ASYNCAXIM_DREX1_3 111 +#define CLK_ACLK_ASYNCAXIS_DREX1_1 112 +#define CLK_ACLK_ASYNCAXIM_DREX1_1 113 +#define CLK_ACLK_ASYNCAXIS_DREX1_0 114 +#define CLK_ACLK_ASYNCAXIM_DREX1_0 115 +#define CLK_ACLK_ASYNCAXIS_DREX0_3 116 +#define CLK_ACLK_ASYNCAXIM_DREX0_3 117 +#define CLK_ACLK_ASYNCAXIS_DREX0_1 118 +#define CLK_ACLK_ASYNCAXIM_DREX0_1 119 +#define CLK_ACLK_ASYNCAXIS_DREX0_0 120 +#define CLK_ACLK_ASYNCAXIM_DREX0_0 121 +#define CLK_ACLK_AHB2APB_MIF2P 122 +#define CLK_ACLK_AHB2APB_MIF1P 123 +#define CLK_ACLK_AHB2APB_MIF0P 124 +#define CLK_ACLK_IXIU_CCI 125 +#define CLK_ACLK_XIU_MIFSFRX 126 +#define CLK_ACLK_MIFNP_133 127 +#define CLK_ACLK_MIFNM_200 128 +#define CLK_ACLK_MIFND_133 129 +#define CLK_ACLK_MIFND_400 130 +#define CLK_ACLK_CCI 131 +#define CLK_ACLK_MIFND_266 132 +#define CLK_ACLK_PPMU_DREX1S3 133 +#define CLK_ACLK_PPMU_DREX1S1 134 +#define CLK_ACLK_PPMU_DREX1S0 135 +#define CLK_ACLK_PPMU_DREX0S3 136 +#define CLK_ACLK_PPMU_DREX0S1 137 +#define CLK_ACLK_PPMU_DREX0S0 138 +#define CLK_ACLK_BTS_APOLLO 139 +#define CLK_ACLK_BTS_ATLAS 140 +#define CLK_ACLK_ACE_SEL_APOLL 141 +#define CLK_ACLK_ACE_SEL_ATLAS 142 +#define CLK_ACLK_AXIDS_CCI_MIFSFRX 143 +#define CLK_ACLK_AXIUS_ATLAS_CCI 144 +#define CLK_ACLK_AXISYNCDNS_CCI 145 +#define CLK_ACLK_AXISYNCDN_CCI 146 +#define CLK_ACLK_AXISYNCDN_NOC_D 147 +#define CLK_ACLK_ASYNCACEM_APOLLO_CCI 148 +#define CLK_ACLK_ASYNCACEM_ATLAS_CCI 149 +#define CLK_ACLK_ASYNCAPBS_MIF_CSSYS 150 +#define CLK_ACLK_BUS2_400 151 +#define CLK_ACLK_DISP_333 152 +#define CLK_ACLK_CPIF_200 153 +#define CLK_PCLK_PPMU_DREX1S3 154 +#define CLK_PCLK_PPMU_DREX1S1 155 +#define CLK_PCLK_PPMU_DREX1S0 156 +#define CLK_PCLK_PPMU_DREX0S3 157 +#define CLK_PCLK_PPMU_DREX0S1 158 +#define CLK_PCLK_PPMU_DREX0S0 159 +#define CLK_PCLK_BTS_APOLLO 160 +#define CLK_PCLK_BTS_ATLAS 161 +#define CLK_PCLK_ASYNCAXI_NOC_P_CCI 162 +#define CLK_PCLK_ASYNCAXI_CP1 163 +#define CLK_PCLK_ASYNCAXI_CP0 164 +#define CLK_PCLK_ASYNCAXI_DREX1_3 165 +#define CLK_PCLK_ASYNCAXI_DREX1_1 166 +#define CLK_PCLK_ASYNCAXI_DREX1_0 167 +#define CLK_PCLK_ASYNCAXI_DREX0_3 168 +#define CLK_PCLK_ASYNCAXI_DREX0_1 169 +#define CLK_PCLK_ASYNCAXI_DREX0_0 170 +#define CLK_PCLK_MIFSRVND_133 171 +#define CLK_PCLK_PMU_MIF 172 +#define CLK_PCLK_SYSREG_MIF 173 +#define CLK_PCLK_GPIO_ALIVE 174 +#define CLK_PCLK_ABB 175 +#define CLK_PCLK_PMU_APBIF 176 +#define CLK_PCLK_DDR_PHY1 177 +#define CLK_PCLK_DREX1 178 +#define CLK_PCLK_DDR_PHY0 179 +#define CLK_PCLK_DREX0 180 +#define CLK_PCLK_DREX0_TZ 181 +#define CLK_PCLK_DREX1_TZ 182 +#define CLK_PCLK_MONOTONIC_CNT 183 +#define CLK_PCLK_RTC 184 +#define CLK_SCLK_DSIM1_DISP 185 +#define CLK_SCLK_DECON_TV_VCLK_DISP 186 +#define CLK_SCLK_FREQ_DET_BUS_PLL 187 +#define CLK_SCLK_FREQ_DET_MFC_PLL 188 +#define CLK_SCLK_FREQ_DET_MEM0_PLL 189 +#define CLK_SCLK_FREQ_DET_MEM1_PLL 190 +#define CLK_SCLK_DSIM0_DISP 191 +#define CLK_SCLK_DSD_DISP 192 +#define CLK_SCLK_DECON_TV_ECLK_DISP 193 +#define CLK_SCLK_DECON_VCLK_DISP 194 +#define CLK_SCLK_DECON_ECLK_DISP 195 +#define CLK_SCLK_HPM_MIF 196 +#define CLK_SCLK_MFC_PLL 197 +#define CLK_SCLK_BUS_PLL 198 +#define CLK_SCLK_BUS_PLL_APOLLO 199 +#define CLK_SCLK_BUS_PLL_ATLAS 200 + +#define MIF_NR_CLK 201 /* CMU_PERIC */ #define CLK_PCLK_SPI2 1 -- cgit v1.2.3 From 2a1808a6c00fb6d75ebfa596add57638b9290926 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:02 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_DISP domain This patch adds the the mux/divider/gate clocks for CMU_DISP domain which includes clocks of the display IPs (DECON/HDMI/DSIM/MIXER). Also, CMU_DISP requires 'sclk_hdmi_spdif_disp' source clock from CMU_TOP domain. This patch adds the clocks of CMU_TOP related to HDMI. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 437 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 114 ++++++++- 2 files changed, 550 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 09ccf11bab64..3e6c3d595e96 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -245,6 +245,8 @@ PNAME(mout_sclk_audio1_p) = { "ioclk_audiocdclk1", "oscclk", PNAME(mout_sclk_audio0_p) = { "ioclk_audiocdclk0", "oscclk", "mout_aud_pll_user_t",}; +PNAME(mout_sclk_hdmi_spdif_p) = { "sclk_audio1", "ioclk_spdif_extclk", }; + static struct samsung_fixed_factor_clock top_fixed_factor_clks[] __initdata = { FFACTOR(0, "oscclk_efuse_common", "oscclk", 1, 1, 0), }; @@ -395,6 +397,10 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX_SEL_TOP_PERIC1, 4, 2), MUX(CLK_MOUT_SCLK_AUDIO0, "mout_sclk_audio0", mout_sclk_audio0_p, MUX_SEL_TOP_PERIC1, 0, 2), + + /* MUX_SEL_TOP_DISP */ + MUX(CLK_MOUT_SCLK_HDMI_SPDIF, "mout_sclk_hdmi_spdif", + mout_sclk_hdmi_spdif_p, MUX_SEL_TOP_DISP, 0, 1), }; static struct samsung_div_clock top_div_clks[] __initdata = { @@ -1360,6 +1366,11 @@ static struct samsung_gate_clock mif_gate_clks[] __initdata = { ENABLE_SCLK_MIF, 1, CLK_IGNORE_UNUSED, 0), GATE(CLK_SCLK_BUS_PLL_ATLAS, "sclk_bus_pll_atlas", "sclk_bus_pll", ENABLE_SCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_TOP_DISP */ + GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp", + "mout_sclk_hdmi_spdif", ENABLE_SCLK_TOP_DISP, 0, + CLK_IGNORE_UNUSED, 0), }; static struct samsung_cmu_info mif_cmu_info __initdata = { @@ -2022,3 +2033,429 @@ static void __init exynos5433_cmu_g2d_init(struct device_node *np) CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d", exynos5433_cmu_g2d_init); + +/* + * Register offset definitions for CMU_DISP + */ +#define DISP_PLL_LOCK 0x0000 +#define DISP_PLL_CON0 0x0100 +#define DISP_PLL_CON1 0x0104 +#define DISP_PLL_FREQ_DET 0x0108 +#define MUX_SEL_DISP0 0x0200 +#define MUX_SEL_DISP1 0x0204 +#define MUX_SEL_DISP2 0x0208 +#define MUX_SEL_DISP3 0x020c +#define MUX_SEL_DISP4 0x0210 +#define MUX_ENABLE_DISP0 0x0300 +#define MUX_ENABLE_DISP1 0x0304 +#define MUX_ENABLE_DISP2 0x0308 +#define MUX_ENABLE_DISP3 0x030c +#define MUX_ENABLE_DISP4 0x0310 +#define MUX_STAT_DISP0 0x0400 +#define MUX_STAT_DISP1 0x0404 +#define MUX_STAT_DISP2 0x0408 +#define MUX_STAT_DISP3 0x040c +#define MUX_STAT_DISP4 0x0410 +#define MUX_IGNORE_DISP2 0x0508 +#define DIV_DISP 0x0600 +#define DIV_DISP_PLL_FREQ_DET 0x0604 +#define DIV_STAT_DISP 0x0700 +#define DIV_STAT_DISP_PLL_FREQ_DET 0x0704 +#define ENABLE_ACLK_DISP0 0x0800 +#define ENABLE_ACLK_DISP1 0x0804 +#define ENABLE_PCLK_DISP 0x0900 +#define ENABLE_SCLK_DISP 0x0a00 +#define ENABLE_IP_DISP0 0x0b00 +#define ENABLE_IP_DISP1 0x0b04 +#define CLKOUT_CMU_DISP 0x0c00 +#define CLKOUT_CMU_DISP_DIV_STAT 0x0c04 + +static unsigned long disp_clk_regs[] __initdata = { + DISP_PLL_LOCK, + DISP_PLL_CON0, + DISP_PLL_CON1, + DISP_PLL_FREQ_DET, + MUX_SEL_DISP0, + MUX_SEL_DISP1, + MUX_SEL_DISP2, + MUX_SEL_DISP3, + MUX_SEL_DISP4, + MUX_ENABLE_DISP0, + MUX_ENABLE_DISP1, + MUX_ENABLE_DISP2, + MUX_ENABLE_DISP3, + MUX_ENABLE_DISP4, + MUX_STAT_DISP0, + MUX_STAT_DISP1, + MUX_STAT_DISP2, + MUX_STAT_DISP3, + MUX_STAT_DISP4, + MUX_IGNORE_DISP2, + DIV_DISP, + DIV_DISP_PLL_FREQ_DET, + DIV_STAT_DISP, + DIV_STAT_DISP_PLL_FREQ_DET, + ENABLE_ACLK_DISP0, + ENABLE_ACLK_DISP1, + ENABLE_PCLK_DISP, + ENABLE_SCLK_DISP, + ENABLE_IP_DISP0, + ENABLE_IP_DISP1, + CLKOUT_CMU_DISP, + CLKOUT_CMU_DISP_DIV_STAT, +}; + +/* list of all parent clock list */ +PNAME(mout_disp_pll_p) = { "oscclk", "fout_disp_pll", }; +PNAME(mout_sclk_dsim1_user_p) = { "oscclk", "sclk_dsim1_disp", }; +PNAME(mout_sclk_dsim0_user_p) = { "oscclk", "sclk_dsim0_disp", }; +PNAME(mout_sclk_dsd_user_p) = { "oscclk", "sclk_dsd_disp", }; +PNAME(mout_sclk_decon_tv_eclk_user_p) = { "oscclk", + "sclk_decon_tv_eclk_disp", }; +PNAME(mout_sclk_decon_vclk_user_p) = { "oscclk", + "sclk_decon_vclk_disp", }; +PNAME(mout_sclk_decon_eclk_user_p) = { "oscclk", + "sclk_decon_eclk_disp", }; +PNAME(mout_sclk_decon_tv_vlkc_user_p) = { "oscclk", + "sclk_decon_tv_vclk_disp", }; +PNAME(mout_aclk_disp_333_user_p) = { "oscclk", "aclk_disp_333", }; + +PNAME(mout_phyclk_mipidphy1_bitclkdiv8_user_p) = { "oscclk", + "phyclk_mipidphy1_bitclkdiv8_phy", }; +PNAME(mout_phyclk_mipidphy1_rxclkesc0_user_p) = { "oscclk", + "phyclk_mipidphy1_rxclkesc0_phy", }; +PNAME(mout_phyclk_mipidphy0_bitclkdiv8_user_p) = { "oscclk", + "phyclk_mipidphy0_bitclkdiv8_phy", }; +PNAME(mout_phyclk_mipidphy0_rxclkesc0_user_p) = { "oscclk", + "phyclk_mipidphy0_rxclkesc0_phy", }; +PNAME(mout_phyclk_hdmiphy_tmds_clko_user_p) = { "oscclk", + "phyclk_hdmiphy_tmds_clko_phy", }; +PNAME(mout_phyclk_hdmiphy_pixel_clko_user_p) = { "oscclk", + "phyclk_hdmiphy_pixel_clko_phy", }; + +PNAME(mout_sclk_dsim0_p) = { "mout_disp_pll", + "mout_sclk_dsim0_user", }; +PNAME(mout_sclk_decon_tv_eclk_p) = { "mout_disp_pll", + "mout_sclk_decon_tv_eclk_user", }; +PNAME(mout_sclk_decon_vclk_p) = { "mout_disp_pll", + "mout_sclk_decon_vclk_user", }; +PNAME(mout_sclk_decon_eclk_p) = { "mout_disp_pll", + "mout_sclk_decon_eclk_user", }; + +PNAME(mout_sclk_dsim1_b_disp_p) = { "mout_sclk_dsim1_a_disp", + "mout_sclk_dsim1_user", }; +PNAME(mout_sclk_decon_tv_vclk_c_disp_p) = { + "mout_phyclk_hdmiphy_pixel_clko_user", + "mout_sclk_decon_tv_vclk_b_disp", }; +PNAME(mout_sclk_decon_tv_vclk_b_disp_p) = { "mout_sclk_decon_tv_vclk_a_disp", + "mout_sclk_decon_tv_vclk_user", }; + +static struct samsung_pll_clock disp_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll", "oscclk", + DISP_PLL_LOCK, DISP_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_fixed_factor_clock disp_fixed_factor_clks[] __initdata = { + /* + * sclk_rgb_{vclk|tv_vclk} is half clock of sclk_decon_{vclk|tv_vclk}. + * The divider has fixed value (2) between sclk_rgb_{vclk|tv_vclk} + * and sclk_decon_{vclk|tv_vclk}. + */ + FFACTOR(CLK_SCLK_RGB_VCLK, "sclk_rgb_vclk", "sclk_decon_vclk", + 1, 2, 0), + FFACTOR(CLK_SCLK_RGB_TV_VCLK, "sclk_rgb_tv_vclk", "sclk_decon_tv_vclk", + 1, 2, 0), +}; + +static struct samsung_fixed_rate_clock disp_fixed_clks[] __initdata = { + /* PHY clocks from MIPI_DPHY1 */ + FRATE(0, "phyclk_mipidphy1_bitclkdiv8_phy", NULL, CLK_IS_ROOT, + 188000000), + FRATE(0, "phyclk_mipidphy1_rxclkesc0_phy", NULL, CLK_IS_ROOT, + 100000000), + /* PHY clocks from MIPI_DPHY0 */ + FRATE(0, "phyclk_mipidphy0_bitclkdiv8_phy", NULL, CLK_IS_ROOT, + 188000000), + FRATE(0, "phyclk_mipidphy0_rxclkesc0_phy", NULL, CLK_IS_ROOT, + 100000000), + /* PHY clocks from HDMI_PHY */ + FRATE(0, "phyclk_hdmiphy_tmds_clko_phy", NULL, CLK_IS_ROOT, 300000000), + FRATE(0, "phyclk_hdmiphy_pixel_clko_phy", NULL, CLK_IS_ROOT, 166000000), +}; + +static struct samsung_mux_clock disp_mux_clks[] __initdata = { + /* MUX_SEL_DISP0 */ + MUX(CLK_MOUT_DISP_PLL, "mout_disp_pll", mout_disp_pll_p, MUX_SEL_DISP0, + 0, 1), + + /* MUX_SEL_DISP1 */ + MUX(CLK_MOUT_SCLK_DSIM1_USER, "mout_sclk_dsim1_user", + mout_sclk_dsim1_user_p, MUX_SEL_DISP1, 28, 1), + MUX(CLK_MOUT_SCLK_DSIM0_USER, "mout_sclk_dsim0_user", + mout_sclk_dsim0_user_p, MUX_SEL_DISP1, 24, 1), + MUX(CLK_MOUT_SCLK_DSD_USER, "mout_sclk_dsd_user", mout_sclk_dsd_user_p, + MUX_SEL_DISP1, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_USER, "mout_sclk_decon_tv_eclk_user", + mout_sclk_decon_tv_eclk_user_p, MUX_SEL_DISP1, 16, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK_USER, "mout_sclk_decon_vclk_user", + mout_sclk_decon_vclk_user_p, MUX_SEL_DISP1, 12, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_USER, "mout_sclk_decon_eclk_user", + mout_sclk_decon_eclk_user_p, MUX_SEL_DISP1, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_USER, "mout_sclk_decon_tv_vclk_user", + mout_sclk_decon_tv_vlkc_user_p, MUX_SEL_DISP1, 4, 1), + MUX(CLK_MOUT_ACLK_DISP_333_USER, "mout_aclk_disp_333_user", + mout_aclk_disp_333_user_p, MUX_SEL_DISP1, 0, 1), + + /* MUX_SEL_DISP2 */ + MUX(CLK_MOUT_PHYCLK_MIPIDPHY1_BITCLKDIV8_USER, + "mout_phyclk_mipidphy1_bitclkdiv8_user", + mout_phyclk_mipidphy1_bitclkdiv8_user_p, MUX_SEL_DISP2, + 20, 1), + MUX(CLK_MOUT_PHYCLK_MIPIDPHY1_RXCLKESC0_USER, + "mout_phyclk_mipidphy1_rxclkesc0_user", + mout_phyclk_mipidphy1_rxclkesc0_user_p, MUX_SEL_DISP2, + 16, 1), + MUX(CLK_MOUT_PHYCLK_MIPIDPHY0_BITCLKDIV8_USER, + "mout_phyclk_mipidphy0_bitclkdiv8_user", + mout_phyclk_mipidphy0_bitclkdiv8_user_p, MUX_SEL_DISP2, + 12, 1), + MUX(CLK_MOUT_PHYCLK_MIPIDPHY0_RXCLKESC0_USER, + "mout_phyclk_mipidphy0_rxclkesc0_user", + mout_phyclk_mipidphy0_rxclkesc0_user_p, MUX_SEL_DISP2, + 8, 1), + MUX(CLK_MOUT_PHYCLK_HDMIPHY_TMDS_CLKO_USER, + "mout_phyclk_hdmiphy_tmds_clko_user", + mout_phyclk_hdmiphy_tmds_clko_user_p, MUX_SEL_DISP2, + 4, 1), + MUX(CLK_MOUT_PHYCLK_HDMIPHY_PIXEL_CLKO_USER, + "mout_phyclk_hdmiphy_pixel_clko_user", + mout_phyclk_hdmiphy_pixel_clko_user_p, MUX_SEL_DISP2, + 0, 1), + + /* MUX_SEL_DISP3 */ + MUX(CLK_MOUT_SCLK_DSIM0, "mout_sclk_dsim0", mout_sclk_dsim0_p, + MUX_SEL_DISP3, 12, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK, "mout_sclk_decon_tv_eclk", + mout_sclk_decon_tv_eclk_p, MUX_SEL_DISP3, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK, "mout_sclk_decon_vclk", + mout_sclk_decon_vclk_p, MUX_SEL_DISP3, 4, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK, "mout_sclk_decon_eclk", + mout_sclk_decon_eclk_p, MUX_SEL_DISP3, 0, 1), + + /* MUX_SEL_DISP4 */ + MUX(CLK_MOUT_SCLK_DSIM1_B_DISP, "mout_sclk_dsim1_b_disp", + mout_sclk_dsim1_b_disp_p, MUX_SEL_DISP4, 16, 1), + MUX(CLK_MOUT_SCLK_DSIM1_A_DISP, "mout_sclk_dsim1_a_disp", + mout_sclk_dsim0_p, MUX_SEL_DISP4, 12, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_C_DISP, + "mout_sclk_decon_tv_vclk_c_disp", + mout_sclk_decon_tv_vclk_c_disp_p, MUX_SEL_DISP4, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_B_DISP, + "mout_sclk_decon_tv_vclk_b_disp", + mout_sclk_decon_tv_vclk_b_disp_p, MUX_SEL_DISP4, 4, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_A_DISP, + "mout_sclk_decon_tv_vclk_a_disp", + mout_sclk_decon_vclk_p, MUX_SEL_DISP4, 0, 1), +}; + +static struct samsung_div_clock disp_div_clks[] __initdata = { + /* DIV_DISP */ + DIV(CLK_DIV_SCLK_DSIM1_DISP, "div_sclk_dsim1_disp", + "mout_sclk_dsim1_b_disp", DIV_DISP, 24, 3), + DIV(CLK_DIV_SCLK_DECON_TV_VCLK_DISP, "div_sclk_decon_tv_vclk_disp", + "mout_sclk_decon_tv_vclk_c_disp", DIV_DISP, 20, 3), + DIV(CLK_DIV_SCLK_DSIM0_DISP, "div_sclk_dsim0_disp", "mout_sclk_dsim0", + DIV_DISP, 16, 3), + DIV(CLK_DIV_SCLK_DECON_TV_ECLK_DISP, "div_sclk_decon_tv_eclk_disp", + "mout_sclk_decon_tv_eclk", DIV_DISP, 12, 3), + DIV(CLK_DIV_SCLK_DECON_VCLK_DISP, "div_sclk_decon_vclk_disp", + "mout_sclk_decon_vclk", DIV_DISP, 8, 3), + DIV(CLK_DIV_SCLK_DECON_ECLK_DISP, "div_sclk_decon_eclk_disp", + "mout_sclk_decon_eclk", DIV_DISP, 4, 3), + DIV(CLK_DIV_PCLK_DISP, "div_pclk_disp", "mout_aclk_disp_333_user", + DIV_DISP, 0, 2), +}; + +static struct samsung_gate_clock disp_gate_clks[] __initdata = { + /* ENABLE_ACLK_DISP0 */ + GATE(CLK_ACLK_DECON_TV, "aclk_decon_tv", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP0, 2, 0, 0), + GATE(CLK_ACLK_DECON, "aclk_decon", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP0, 0, 0, 0), + + /* ENABLE_ACLK_DISP1 */ + GATE(CLK_ACLK_SMMU_TV1X, "aclk_smmu_tv1x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 25, 0, 0), + GATE(CLK_ACLK_SMMU_TV0X, "aclk_smmu_tv0x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 24, 0, 0), + GATE(CLK_ACLK_SMMU_DECON1X, "aclk_smmu_decon1x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 23, 0, 0), + GATE(CLK_ACLK_SMMU_DECON0X, "aclk_smmu_decon0x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 22, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M3, "aclk_bts_decon_tv_m3", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 21, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M2, "aclk_bts_decon_tv_m2", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 20, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M1, "aclk_bts_decon_tv_m1", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 19, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M0, "aclk-bts_decon_tv_m0", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 18, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM4, "aclk_bts_decon_nm4", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 17, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM3, "aclk_bts_decon_nm3", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 16, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM2, "aclk_bts_decon_nm2", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 15, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM1, "aclk_bts_decon_nm1", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 14, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM0, "aclk_bts_decon_nm0", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 13, 0, 0), + GATE(CLK_ACLK_AHB2APB_DISPSFR2P, "aclk_ahb2apb_dispsfr2p", + "div_pclk_disp", ENABLE_ACLK_DISP1, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_DISPSFR1P, "aclk_ahb2apb_dispsfr1p", + "div_pclk_disp", ENABLE_ACLK_DISP1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_DISPSFR0P, "aclk_ahb2apb_dispsfr0p", + "div_pclk_disp", ENABLE_ACLK_DISP1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_DISPH, "aclk_ahb_disph", "div_pclk_disp", + ENABLE_ACLK_DISP1, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_TV1X, "aclk_xiu_tv1x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 7, 0, 0), + GATE(CLK_ACLK_XIU_TV0X, "aclk_xiu_tv0x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 6, 0, 0), + GATE(CLK_ACLK_XIU_DECON1X, "aclk_xiu_decon1x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 5, 0, 0), + GATE(CLK_ACLK_XIU_DECON0X, "aclk_xiu_decon0x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 4, 0, 0), + GATE(CLK_ACLK_XIU_DISP1X, "aclk_xiu_disp1x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_DISPNP_100, "aclk_xiu_dispnp_100", "div_pclk_disp", + ENABLE_ACLK_DISP1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DISP1ND_333, "aclk_disp1nd_333", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 1, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DISP0ND_333, "aclk_disp0nd_333", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_DISP */ + GATE(CLK_PCLK_SMMU_TV1X, "pclk_smmu_tv1x", "div_pclk_disp", + ENABLE_PCLK_DISP, 23, 0, 0), + GATE(CLK_PCLK_SMMU_TV0X, "pclk_smmu_tv0x", "div_pclk_disp", + ENABLE_PCLK_DISP, 22, 0, 0), + GATE(CLK_PCLK_SMMU_DECON1X, "pclk_smmu_decon1x", "div_pclk_disp", + ENABLE_PCLK_DISP, 21, 0, 0), + GATE(CLK_PCLK_SMMU_DECON0X, "pclk_smmu_decon0x", "div_pclk_disp", + ENABLE_PCLK_DISP, 20, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M3, "pclk_bts_decon_tv_m3", "div_pclk_disp", + ENABLE_PCLK_DISP, 19, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M2, "pclk_bts_decon_tv_m2", "div_pclk_disp", + ENABLE_PCLK_DISP, 18, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M1, "pclk_bts_decon_tv_m1", "div_pclk_disp", + ENABLE_PCLK_DISP, 17, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M0, "pclk_bts_decon_tv_m0", "div_pclk_disp", + ENABLE_PCLK_DISP, 16, 0, 0), + GATE(CLK_PCLK_BTS_DECONM4, "pclk_bts_deconm4", "div_pclk_disp", + ENABLE_PCLK_DISP, 15, 0, 0), + GATE(CLK_PCLK_BTS_DECONM3, "pclk_bts_deconm3", "div_pclk_disp", + ENABLE_PCLK_DISP, 14, 0, 0), + GATE(CLK_PCLK_BTS_DECONM2, "pclk_bts_deconm2", "div_pclk_disp", + ENABLE_PCLK_DISP, 13, 0, 0), + GATE(CLK_PCLK_BTS_DECONM1, "pclk_bts_deconm1", "div_pclk_disp", + ENABLE_PCLK_DISP, 12, 0, 0), + GATE(CLK_PCLK_BTS_DECONM0, "pclk_bts_deconm0", "div_pclk_disp", + ENABLE_PCLK_DISP, 11, 0, 0), + GATE(CLK_PCLK_MIC1, "pclk_mic1", "div_pclk_disp", + ENABLE_PCLK_DISP, 10, 0, 0), + GATE(CLK_PCLK_PMU_DISP, "pclk_pmu_disp", "div_pclk_disp", + ENABLE_PCLK_DISP, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_DISP, "pclk_sysreg_disp", "div_pclk_disp", + ENABLE_PCLK_DISP, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_HDMIPHY, "pclk_hdmiphy", "div_pclk_disp", + ENABLE_PCLK_DISP, 7, 0, 0), + GATE(CLK_PCLK_HDMI, "pclk_hdmi", "div_pclk_disp", + ENABLE_PCLK_DISP, 6, 0, 0), + GATE(CLK_PCLK_MIC0, "pclk_mic0", "div_pclk_disp", + ENABLE_PCLK_DISP, 5, 0, 0), + GATE(CLK_PCLK_DSIM1, "pclk_dsim1", "div_pclk_disp", + ENABLE_PCLK_DISP, 3, 0, 0), + GATE(CLK_PCLK_DSIM0, "pclk_dsim0", "div_pclk_disp", + ENABLE_PCLK_DISP, 2, 0, 0), + GATE(CLK_PCLK_DECON_TV, "pclk_decon_tv", "div_pclk_disp", + ENABLE_PCLK_DISP, 1, 0, 0), + + /* ENABLE_SCLK_DISP */ + GATE(CLK_PHYCLK_MIPIDPHY1_BITCLKDIV8, "phyclk_mipidphy1_bitclkdiv8", + "mout_phyclk_mipidphy1_bitclkdiv8_user", + ENABLE_SCLK_DISP, 26, 0, 0), + GATE(CLK_PHYCLK_MIPIDPHY1_RXCLKESC0, "phyclk_mipidphy1_rxclkesc0", + "mout_phyclk_mipidphy1_rxclkesc0_user", + ENABLE_SCLK_DISP, 25, 0, 0), + GATE(CLK_SCLK_RGB_TV_VCLK_TO_DSIM1, "sclk_rgb_tv_vclk_to_dsim1", + "sclk_rgb_tv_vclk", ENABLE_SCLK_DISP, 24, 0, 0), + GATE(CLK_SCLK_RGB_TV_VCLK_TO_MIC1, "sclk_rgb_tv_vclk_to_mic1", + "sclk_rgb_tv_vclk", ENABLE_SCLK_DISP, 23, 0, 0), + GATE(CLK_SCLK_DSIM1, "sclk_dsim1", "div_sclk_dsim1_disp", + ENABLE_SCLK_DISP, 22, 0, 0), + GATE(CLK_SCLK_DECON_TV_VCLK, "sclk_decon_tv_vclk", + "div_sclk_decon_tv_vclk_disp", + ENABLE_SCLK_DISP, 21, 0, 0), + GATE(CLK_PHYCLK_MIPIDPHY0_BITCLKDIV8, "phyclk_mipidphy0_bitclkdiv8", + "mout_phyclk_mipidphy0_bitclkdiv8_user", + ENABLE_SCLK_DISP, 15, 0, 0), + GATE(CLK_PHYCLK_MIPIDPHY0_RXCLKESC0, "phyclk_mipidphy0_rxclkesc0", + "mout_phyclk_mipidphy0_rxclkesc0_user", + ENABLE_SCLK_DISP, 14, 0, 0), + GATE(CLK_PHYCLK_HDMIPHY_TMDS_CLKO, "phyclk_hdmiphy_tmds_clko", + "mout_phyclk_hdmiphy_tmds_clko_user", + ENABLE_SCLK_DISP, 13, 0, 0), + GATE(CLK_PHYCLK_HDMI_PIXEL, "phyclk_hdmi_pixel", + "sclk_rgb_tv_vclk", ENABLE_SCLK_DISP, 12, 0, 0), + GATE(CLK_SCLK_RGB_VCLK_TO_SMIES, "sclk_rgb_vclk_to_smies", + "sclk_rgb_vclk", ENABLE_SCLK_DISP, 11, 0, 0), + GATE(CLK_SCLK_RGB_VCLK_TO_DSIM0, "sclk_rgb_vclk_to_dsim0", + "sclk_rgb_vclk", ENABLE_SCLK_DISP, 9, 0, 0), + GATE(CLK_SCLK_RGB_VCLK_TO_MIC0, "sclk_rgb_vclk_to_mic0", + "sclk_rgb_vclk", ENABLE_SCLK_DISP, 8, 0, 0), + GATE(CLK_SCLK_DSD, "sclk_dsd", "mout_sclk_dsd_user", + ENABLE_SCLK_DISP, 7, 0, 0), + GATE(CLK_SCLK_HDMI_SPDIF, "sclk_hdmi_spdif", "sclk_hdmi_spdif_disp", + ENABLE_SCLK_DISP, 6, 0, 0), + GATE(CLK_SCLK_DSIM0, "sclk_dsim0", "div_sclk_dsim0_disp", + ENABLE_SCLK_DISP, 5, 0, 0), + GATE(CLK_SCLK_DECON_TV_ECLK, "sclk_decon_tv_eclk", + "div_sclk_decon_tv_eclk_disp", + ENABLE_SCLK_DISP, 4, 0, 0), + GATE(CLK_SCLK_DECON_VCLK, "sclk_decon_vclk", + "div_sclk_decon_vclk_disp", ENABLE_SCLK_DISP, 3, 0, 0), + GATE(CLK_SCLK_DECON_ECLK, "sclk_decon_eclk", + "div_sclk_decon_eclk_disp", ENABLE_SCLK_DISP, 2, 0, 0), +}; + +static struct samsung_cmu_info disp_cmu_info __initdata = { + .pll_clks = disp_pll_clks, + .nr_pll_clks = ARRAY_SIZE(disp_pll_clks), + .mux_clks = disp_mux_clks, + .nr_mux_clks = ARRAY_SIZE(disp_mux_clks), + .div_clks = disp_div_clks, + .nr_div_clks = ARRAY_SIZE(disp_div_clks), + .gate_clks = disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(disp_gate_clks), + .fixed_clks = disp_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(disp_fixed_clks), + .fixed_factor_clks = disp_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(disp_fixed_factor_clks), + .nr_clk_ids = DISP_NR_CLK, + .clk_regs = disp_clk_regs, + .nr_clk_regs = ARRAY_SIZE(disp_clk_regs), +}; + +static void __init exynos5433_cmu_disp_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &disp_cmu_info); +} + +CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp", + exynos5433_cmu_disp_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 6a3ce113e1e5..fe0650fad766 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -68,6 +68,7 @@ #define CLK_MOUT_SCLK_SPDIF 61 #define CLK_MOUT_SCLK_AUDIO1 62 #define CLK_MOUT_SCLK_AUDIO0 63 +#define CLK_MOUT_SCLK_HDMI_SPDIF 64 #define CLK_DIV_ACLK_FSYS_200 100 #define CLK_DIV_ACLK_IMEM_SSSX_266 101 @@ -337,8 +338,9 @@ #define CLK_SCLK_BUS_PLL 198 #define CLK_SCLK_BUS_PLL_APOLLO 199 #define CLK_SCLK_BUS_PLL_ATLAS 200 +#define CLK_SCLK_HDMI_SPDIF_DISP 201 -#define MIF_NR_CLK 201 +#define MIF_NR_CLK 202 /* CMU_PERIC */ #define CLK_PCLK_SPI2 1 @@ -514,4 +516,114 @@ #define G2D_NR_CLK 27 +/* CMU_DISP */ +#define CLK_FOUT_DISP_PLL 1 + +#define CLK_MOUT_DISP_PLL 2 +#define CLK_MOUT_SCLK_DSIM1_USER 3 +#define CLK_MOUT_SCLK_DSIM0_USER 4 +#define CLK_MOUT_SCLK_DSD_USER 5 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_USER 6 +#define CLK_MOUT_SCLK_DECON_VCLK_USER 7 +#define CLK_MOUT_SCLK_DECON_ECLK_USER 8 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_USER 9 +#define CLK_MOUT_ACLK_DISP_333_USER 10 +#define CLK_MOUT_PHYCLK_MIPIDPHY1_BITCLKDIV8_USER 11 +#define CLK_MOUT_PHYCLK_MIPIDPHY1_RXCLKESC0_USER 12 +#define CLK_MOUT_PHYCLK_MIPIDPHY0_BITCLKDIV8_USER 13 +#define CLK_MOUT_PHYCLK_MIPIDPHY0_RXCLKESC0_USER 14 +#define CLK_MOUT_PHYCLK_HDMIPHY_TMDS_CLKO_USER 15 +#define CLK_MOUT_PHYCLK_HDMIPHY_PIXEL_CLKO_USER 16 +#define CLK_MOUT_SCLK_DSIM0 17 +#define CLK_MOUT_SCLK_DECON_TV_ECLK 18 +#define CLK_MOUT_SCLK_DECON_VCLK 19 +#define CLK_MOUT_SCLK_DECON_ECLK 20 +#define CLK_MOUT_SCLK_DSIM1_B_DISP 21 +#define CLK_MOUT_SCLK_DSIM1_A_DISP 22 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_C_DISP 23 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_B_DISP 24 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_A_DISP 25 + +#define CLK_DIV_SCLK_DSIM1_DISP 30 +#define CLK_DIV_SCLK_DECON_TV_VCLK_DISP 31 +#define CLK_DIV_SCLK_DSIM0_DISP 32 +#define CLK_DIV_SCLK_DECON_TV_ECLK_DISP 33 +#define CLK_DIV_SCLK_DECON_VCLK_DISP 34 +#define CLK_DIV_SCLK_DECON_ECLK_DISP 35 +#define CLK_DIV_PCLK_DISP 36 + +#define CLK_ACLK_DECON_TV 40 +#define CLK_ACLK_DECON 41 +#define CLK_ACLK_SMMU_TV1X 42 +#define CLK_ACLK_SMMU_TV0X 43 +#define CLK_ACLK_SMMU_DECON1X 44 +#define CLK_ACLK_SMMU_DECON0X 45 +#define CLK_ACLK_BTS_DECON_TV_M3 46 +#define CLK_ACLK_BTS_DECON_TV_M2 47 +#define CLK_ACLK_BTS_DECON_TV_M1 48 +#define CLK_ACLK_BTS_DECON_TV_M0 49 +#define CLK_ACLK_BTS_DECON_NM4 50 +#define CLK_ACLK_BTS_DECON_NM3 51 +#define CLK_ACLK_BTS_DECON_NM2 52 +#define CLK_ACLK_BTS_DECON_NM1 53 +#define CLK_ACLK_BTS_DECON_NM0 54 +#define CLK_ACLK_AHB2APB_DISPSFR2P 55 +#define CLK_ACLK_AHB2APB_DISPSFR1P 56 +#define CLK_ACLK_AHB2APB_DISPSFR0P 57 +#define CLK_ACLK_AHB_DISPH 58 +#define CLK_ACLK_XIU_TV1X 59 +#define CLK_ACLK_XIU_TV0X 60 +#define CLK_ACLK_XIU_DECON1X 61 +#define CLK_ACLK_XIU_DECON0X 62 +#define CLK_ACLK_XIU_DISP1X 63 +#define CLK_ACLK_XIU_DISPNP_100 64 +#define CLK_ACLK_DISP1ND_333 65 +#define CLK_ACLK_DISP0ND_333 66 +#define CLK_PCLK_SMMU_TV1X 67 +#define CLK_PCLK_SMMU_TV0X 68 +#define CLK_PCLK_SMMU_DECON1X 69 +#define CLK_PCLK_SMMU_DECON0X 70 +#define CLK_PCLK_BTS_DECON_TV_M3 71 +#define CLK_PCLK_BTS_DECON_TV_M2 72 +#define CLK_PCLK_BTS_DECON_TV_M1 73 +#define CLK_PCLK_BTS_DECON_TV_M0 74 +#define CLK_PCLK_BTS_DECONM4 75 +#define CLK_PCLK_BTS_DECONM3 76 +#define CLK_PCLK_BTS_DECONM2 77 +#define CLK_PCLK_BTS_DECONM1 78 +#define CLK_PCLK_BTS_DECONM0 79 +#define CLK_PCLK_MIC1 80 +#define CLK_PCLK_PMU_DISP 81 +#define CLK_PCLK_SYSREG_DISP 82 +#define CLK_PCLK_HDMIPHY 83 +#define CLK_PCLK_HDMI 84 +#define CLK_PCLK_MIC0 85 +#define CLK_PCLK_DSIM1 86 +#define CLK_PCLK_DSIM0 87 +#define CLK_PCLK_DECON_TV 88 +#define CLK_PHYCLK_MIPIDPHY1_BITCLKDIV8 89 +#define CLK_PHYCLK_MIPIDPHY1_RXCLKESC0 90 +#define CLK_SCLK_RGB_TV_VCLK_TO_DSIM1 91 +#define CLK_SCLK_RGB_TV_VCLK_TO_MIC1 92 +#define CLK_SCLK_DSIM1 93 +#define CLK_SCLK_DECON_TV_VCLK 94 +#define CLK_PHYCLK_MIPIDPHY0_BITCLKDIV8 95 +#define CLK_PHYCLK_MIPIDPHY0_RXCLKESC0 96 +#define CLK_PHYCLK_HDMIPHY_TMDS_CLKO 97 +#define CLK_PHYCLK_HDMI_PIXEL 98 +#define CLK_SCLK_RGB_VCLK_TO_SMIES 99 +#define CLK_SCLK_FREQ_DET_DISP_PLL 100 +#define CLK_SCLK_RGB_VCLK_TO_DSIM0 101 +#define CLK_SCLK_RGB_VCLK_TO_MIC0 102 +#define CLK_SCLK_DSD 103 +#define CLK_SCLK_HDMI_SPDIF 104 +#define CLK_SCLK_DSIM0 105 +#define CLK_SCLK_DECON_TV_ECLK 106 +#define CLK_SCLK_DECON_VCLK 107 +#define CLK_SCLK_DECON_ECLK 108 +#define CLK_SCLK_RGB_VCLK 109 +#define CLK_SCLK_RGB_TV_VCLK 110 + +#define DISP_NR_CLK 111 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 2e997c035945784fb8c564305c0f0ddacc374fe4 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:03 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_AUD domain This patch adds the mux/divider/gate clocks for CMU_AUD domain which includes the clocks of Cortex-A5/Bus/Audio clocks. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 172 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 53 ++++++++++ 2 files changed, 225 insertions(+) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 3e6c3d595e96..ad0105aa0de6 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -2459,3 +2459,175 @@ static void __init exynos5433_cmu_disp_init(struct device_node *np) CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp", exynos5433_cmu_disp_init); + +/* + * Register offset definitions for CMU_AUD + */ +#define MUX_SEL_AUD0 0x0200 +#define MUX_SEL_AUD1 0x0204 +#define MUX_ENABLE_AUD0 0x0300 +#define MUX_ENABLE_AUD1 0x0304 +#define MUX_STAT_AUD0 0x0400 +#define DIV_AUD0 0x0600 +#define DIV_AUD1 0x0604 +#define DIV_STAT_AUD0 0x0700 +#define DIV_STAT_AUD1 0x0704 +#define ENABLE_ACLK_AUD 0x0800 +#define ENABLE_PCLK_AUD 0x0900 +#define ENABLE_SCLK_AUD0 0x0a00 +#define ENABLE_SCLK_AUD1 0x0a04 +#define ENABLE_IP_AUD0 0x0b00 +#define ENABLE_IP_AUD1 0x0b04 + +static unsigned long aud_clk_regs[] __initdata = { + MUX_SEL_AUD0, + MUX_SEL_AUD1, + MUX_ENABLE_AUD0, + MUX_ENABLE_AUD1, + MUX_STAT_AUD0, + DIV_AUD0, + DIV_AUD1, + DIV_STAT_AUD0, + DIV_STAT_AUD1, + ENABLE_ACLK_AUD, + ENABLE_PCLK_AUD, + ENABLE_SCLK_AUD0, + ENABLE_SCLK_AUD1, + ENABLE_IP_AUD0, + ENABLE_IP_AUD1, +}; + +/* list of all parent clock list */ +PNAME(mout_aud_pll_user_aud_p) = { "oscclk", "fout_aud_pll", }; +PNAME(mout_sclk_aud_pcm_p) = { "mout_aud_pll_user", "ioclk_audiocdclk0",}; + +static struct samsung_fixed_rate_clock aud_fixed_clks[] __initdata = { + FRATE(0, "ioclk_jtag_tclk", NULL, CLK_IS_ROOT, 33000000), + FRATE(0, "ioclk_slimbus_clk", NULL, CLK_IS_ROOT, 25000000), + FRATE(0, "ioclk_i2s_bclk", NULL, CLK_IS_ROOT, 50000000), +}; + +static struct samsung_mux_clock aud_mux_clks[] __initdata = { + /* MUX_SEL_AUD0 */ + MUX(CLK_MOUT_AUD_PLL_USER, "mout_aud_pll_user", + mout_aud_pll_user_aud_p, MUX_SEL_AUD0, 0, 1), + + /* MUX_SEL_AUD1 */ + MUX(CLK_MOUT_SCLK_AUD_PCM, "mout_sclk_aud_pcm", mout_sclk_aud_pcm_p, + MUX_SEL_AUD1, 8, 1), + MUX(CLK_MOUT_SCLK_AUD_I2S, "mout_sclk_aud_i2s", mout_sclk_aud_pcm_p, + MUX_SEL_AUD1, 0, 1), +}; + +static struct samsung_div_clock aud_div_clks[] __initdata = { + /* DIV_AUD0 */ + DIV(CLK_DIV_ATCLK_AUD, "div_atclk_aud", "div_aud_ca5", DIV_AUD0, + 12, 4), + DIV(CLK_DIV_PCLK_DBG_AUD, "div_pclk_dbg_aud", "div_aud_ca5", DIV_AUD0, + 8, 4), + DIV(CLK_DIV_ACLK_AUD, "div_aclk_aud", "div_aud_ca5", DIV_AUD0, + 4, 4), + DIV(CLK_DIV_AUD_CA5, "div_aud_ca5", "mout_aud_pll_user", DIV_AUD0, + 0, 4), + + /* DIV_AUD1 */ + DIV(CLK_DIV_SCLK_AUD_SLIMBUS, "div_sclk_aud_slimbus", + "mout_aud_pll_user", DIV_AUD1, 16, 5), + DIV(CLK_DIV_SCLK_AUD_UART, "div_sclk_aud_uart", "mout_aud_pll_user", + DIV_AUD1, 12, 4), + DIV(CLK_DIV_SCLK_AUD_PCM, "div_sclk_aud_pcm", "mout_sclk_aud_pcm", + DIV_AUD1, 4, 8), + DIV(CLK_DIV_SCLK_AUD_I2S, "div_sclk_aud_i2s", "mout_sclk_aud_i2s", + DIV_AUD1, 0, 4), +}; + +static struct samsung_gate_clock aud_gate_clks[] __initdata = { + /* ENABLE_ACLK_AUD */ + GATE(CLK_ACLK_INTR_CTRL, "aclk_intr_ctrl", "div_aclk_aud", + ENABLE_ACLK_AUD, 12, 0, 0), + GATE(CLK_ACLK_SMMU_LPASSX, "aclk_smmu_lpassx", "div_aclk_aud", + ENABLE_ACLK_AUD, 7, 0, 0), + GATE(CLK_ACLK_XIU_LPASSX, "aclk_xiu_lpassx", "div_aclk_aud", + ENABLE_ACLK_AUD, 0, 4, 0), + GATE(CLK_ACLK_AUDNP_133, "aclk_audnp_133", "div_aclk_aud", + ENABLE_ACLK_AUD, 0, 3, 0), + GATE(CLK_ACLK_AUDND_133, "aclk_audnd_133", "div_aclk_aud", + ENABLE_ACLK_AUD, 0, 2, 0), + GATE(CLK_ACLK_SRAMC, "aclk_sramc", "div_aclk_aud", ENABLE_ACLK_AUD, + 0, 1, 0), + GATE(CLK_ACLK_DMAC, "aclk_dmac", "div_aclk_aud", ENABLE_ACLK_AUD, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_AUD */ + GATE(CLK_PCLK_WDT1, "pclk_wdt1", "div_aclk_aud", ENABLE_PCLK_AUD, + 13, 0, 0), + GATE(CLK_PCLK_WDT0, "pclk_wdt0", "div_aclk_aud", ENABLE_PCLK_AUD, + 12, 0, 0), + GATE(CLK_PCLK_SFR1, "pclk_sfr1", "div_aclk_aud", ENABLE_PCLK_AUD, + 11, 0, 0), + GATE(CLK_PCLK_SMMU_LPASSX, "pclk_smmu_lpassx", "div_aclk_aud", + ENABLE_PCLK_AUD, 10, 0, 0), + GATE(CLK_PCLK_GPIO_AUD, "pclk_gpio_aud", "div_aclk_aud", + ENABLE_PCLK_AUD, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_AUD, "pclk_pmu_aud", "div_aclk_aud", + ENABLE_PCLK_AUD, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_AUD, "pclk_sysreg_aud", "div_aclk_aud", + ENABLE_PCLK_AUD, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_AUD_SLIMBUS, "pclk_aud_slimbus", "div_aclk_aud", + ENABLE_PCLK_AUD, 6, 0, 0), + GATE(CLK_PCLK_AUD_UART, "pclk_aud_uart", "div_aclk_aud", + ENABLE_PCLK_AUD, 5, 0, 0), + GATE(CLK_PCLK_AUD_PCM, "pclk_aud_pcm", "div_aclk_aud", + ENABLE_PCLK_AUD, 4, 0, 0), + GATE(CLK_PCLK_AUD_I2S, "pclk_aud_i2s", "div_aclk_aud", + ENABLE_PCLK_AUD, 3, 0, 0), + GATE(CLK_PCLK_TIMER, "pclk_timer", "div_aclk_aud", ENABLE_PCLK_AUD, + 2, 0, 0), + GATE(CLK_PCLK_SFR0_CTRL, "pclk_sfr0_ctrl", "div_aclk_aud", + ENABLE_PCLK_AUD, 0, 0, 0), + + /* ENABLE_SCLK_AUD0 */ + GATE(CLK_ATCLK_AUD, "atclk_aud", "div_atclk_aud", ENABLE_SCLK_AUD0, + 2, 0, 0), + GATE(CLK_PCLK_DBG_AUD, "pclk_dbg_aud", "div_pclk_dbg_aud", + ENABLE_SCLK_AUD0, 1, 0, 0), + GATE(CLK_SCLK_AUD_CA5, "sclk_aud_ca5", "div_aud_ca5", ENABLE_SCLK_AUD0, + 0, 0, 0), + + /* ENABLE_SCLK_AUD1 */ + GATE(CLK_SCLK_JTAG_TCK, "sclk_jtag_tck", "ioclk_jtag_tclk", + ENABLE_SCLK_AUD1, 6, 0, 0), + GATE(CLK_SCLK_SLIMBUS_CLKIN, "sclk_slimbus_clkin", "ioclk_slimbus_clk", + ENABLE_SCLK_AUD1, 5, 0, 0), + GATE(CLK_SCLK_AUD_SLIMBUS, "sclk_aud_slimbus", "div_sclk_aud_slimbus", + ENABLE_SCLK_AUD1, 4, 0, 0), + GATE(CLK_SCLK_AUD_UART, "sclk_aud_uart", "div_sclk_aud_uart", + ENABLE_SCLK_AUD1, 3, 0, 0), + GATE(CLK_SCLK_AUD_PCM, "sclk_aud_pcm", "div_sclk_aud_pcm", + ENABLE_SCLK_AUD1, 2, 0, 0), + GATE(CLK_SCLK_I2S_BCLK, "sclk_i2s_bclk", "ioclk_i2s_bclk", + ENABLE_SCLK_AUD1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_AUD_I2S, "sclk_aud_i2s", "div_sclk_aud_i2s", + ENABLE_SCLK_AUD1, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info aud_cmu_info __initdata = { + .mux_clks = aud_mux_clks, + .nr_mux_clks = ARRAY_SIZE(aud_mux_clks), + .div_clks = aud_div_clks, + .nr_div_clks = ARRAY_SIZE(aud_div_clks), + .gate_clks = aud_gate_clks, + .nr_gate_clks = ARRAY_SIZE(aud_gate_clks), + .fixed_clks = aud_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(aud_fixed_clks), + .nr_clk_ids = AUD_NR_CLK, + .clk_regs = aud_clk_regs, + .nr_clk_regs = ARRAY_SIZE(aud_clk_regs), +}; + +static void __init exynos5433_cmu_aud_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &aud_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud", + exynos5433_cmu_aud_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index fe0650fad766..4d150e244057 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -626,4 +626,57 @@ #define DISP_NR_CLK 111 +/* CMU_AUD */ +#define CLK_MOUT_AUD_PLL_USER 1 +#define CLK_MOUT_SCLK_AUD_PCM 2 +#define CLK_MOUT_SCLK_AUD_I2S 3 + +#define CLK_DIV_ATCLK_AUD 4 +#define CLK_DIV_PCLK_DBG_AUD 5 +#define CLK_DIV_ACLK_AUD 6 +#define CLK_DIV_AUD_CA5 7 +#define CLK_DIV_SCLK_AUD_SLIMBUS 8 +#define CLK_DIV_SCLK_AUD_UART 9 +#define CLK_DIV_SCLK_AUD_PCM 10 +#define CLK_DIV_SCLK_AUD_I2S 11 + +#define CLK_ACLK_INTR_CTRL 12 +#define CLK_ACLK_AXIDS2_LPASSP 13 +#define CLK_ACLK_AXIDS1_LPASSP 14 +#define CLK_ACLK_AXI2APB1_LPASSP 15 +#define CLK_ACLK_AXI2APH_LPASSP 16 +#define CLK_ACLK_SMMU_LPASSX 17 +#define CLK_ACLK_AXIDS0_LPASSP 18 +#define CLK_ACLK_AXI2APB0_LPASSP 19 +#define CLK_ACLK_XIU_LPASSX 20 +#define CLK_ACLK_AUDNP_133 21 +#define CLK_ACLK_AUDND_133 22 +#define CLK_ACLK_SRAMC 23 +#define CLK_ACLK_DMAC 24 +#define CLK_PCLK_WDT1 25 +#define CLK_PCLK_WDT0 26 +#define CLK_PCLK_SFR1 27 +#define CLK_PCLK_SMMU_LPASSX 28 +#define CLK_PCLK_GPIO_AUD 29 +#define CLK_PCLK_PMU_AUD 30 +#define CLK_PCLK_SYSREG_AUD 31 +#define CLK_PCLK_AUD_SLIMBUS 32 +#define CLK_PCLK_AUD_UART 33 +#define CLK_PCLK_AUD_PCM 34 +#define CLK_PCLK_AUD_I2S 35 +#define CLK_PCLK_TIMER 36 +#define CLK_PCLK_SFR0_CTRL 37 +#define CLK_ATCLK_AUD 38 +#define CLK_PCLK_DBG_AUD 39 +#define CLK_SCLK_AUD_CA5 40 +#define CLK_SCLK_JTAG_TCK 41 +#define CLK_SCLK_SLIMBUS_CLKIN 42 +#define CLK_SCLK_AUD_SLIMBUS 43 +#define CLK_SCLK_AUD_UART 44 +#define CLK_SCLK_AUD_PCM 45 +#define CLK_SCLK_I2S_BCLK 46 +#define CLK_SCLK_AUD_I2S 47 + +#define AUD_NR_CLK 48 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 5785d6e61f27f7af4d239c1647d5a22e0dbff19b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:04 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_BUS{0|1|2} domains This patch adds the mux/divider/gate clocks for CMU_BUS{0|1|2} domains which contain global data buses clocked at up the 400MHz. These blocks transfer data between DRAM and various sub-blocks. These clock domains also contain global peripheral buses clocked at 67/111/200/222/266/333/400 MHz and used for register accesses. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 187 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 27 ++++- 2 files changed, 213 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index ad0105aa0de6..7c4e91a440e5 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -438,6 +438,14 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_ACLK_PERIS_66_A, "div_aclk_peris_66_a", "mout_bus_pll_user", DIV_TOP3, 0, 3), + /* DIV_TOP4 */ + DIV(CLK_DIV_ACLK_G3D_400, "div_aclk_g3d_400", "mout_bus_pll_user", + DIV_TOP4, 8, 3), + DIV(CLK_DIV_ACLK_BUS0_400, "div_aclk_bus0_400", "mout_aclk_bus0_400", + DIV_TOP4, 4, 3), + DIV(CLK_DIV_ACLK_BUS1_400, "div_aclk_bus1_400", "mout_bus_pll_user", + DIV_TOP4, 0, 3), + /* DIV_TOP_FSYS0 */ DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", DIV_TOP_FSYS0, 16, 8), @@ -501,6 +509,23 @@ static struct samsung_div_clock top_div_clks[] __initdata = { static struct samsung_gate_clock top_gate_clks[] __initdata = { /* ENABLE_ACLK_TOP */ + GATE(CLK_ACLK_G3D_400, "aclk_g3d_400", "div_aclk_g3d_400", + ENABLE_ACLK_TOP, 30, 0, 0), + GATE(CLK_ACLK_IMEM_SSX_266, "aclk_imem_ssx_266", + "div_aclk_imem_sssx_266", ENABLE_ACLK_TOP, + 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUS0_400, "aclk_bus0_400", "div_aclk_bus0_400", + ENABLE_ACLK_TOP, 26, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_BUS1_400, "aclk_bus1_400", "div_aclk_bus1_400", + ENABLE_ACLK_TOP, 25, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_IMEM_200, "aclk_imem_200", "div_aclk_imem_266", + ENABLE_ACLK_TOP, 24, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_IMEM_266, "aclk_imem_266", "div_aclk_imem_200", + ENABLE_ACLK_TOP, 23, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), GATE(CLK_ACLK_PERIC_66, "aclk_peric_66", "div_aclk_peric_66_b", ENABLE_ACLK_TOP, 22, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -2631,3 +2656,165 @@ static void __init exynos5433_cmu_aud_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud", exynos5433_cmu_aud_init); + + +/* + * Register offset definitions for CMU_BUS{0|1|2} + */ +#define DIV_BUS 0x0600 +#define DIV_STAT_BUS 0x0700 +#define ENABLE_ACLK_BUS 0x0800 +#define ENABLE_PCLK_BUS 0x0900 +#define ENABLE_IP_BUS0 0x0b00 +#define ENABLE_IP_BUS1 0x0b04 + +#define MUX_SEL_BUS2 0x0200 /* Only for CMU_BUS2 */ +#define MUX_ENABLE_BUS2 0x0300 /* Only for CMU_BUS2 */ +#define MUX_STAT_BUS2 0x0400 /* Only for CMU_BUS2 */ + +/* list of all parent clock list */ +PNAME(mout_aclk_bus2_400_p) = { "oscclk", "aclk_bus2_400", }; + +#define CMU_BUS_COMMON_CLK_REGS \ + DIV_BUS, \ + DIV_STAT_BUS, \ + ENABLE_ACLK_BUS, \ + ENABLE_PCLK_BUS, \ + ENABLE_IP_BUS0, \ + ENABLE_IP_BUS1 + +static unsigned long bus01_clk_regs[] __initdata = { + CMU_BUS_COMMON_CLK_REGS, +}; + +static unsigned long bus2_clk_regs[] __initdata = { + MUX_SEL_BUS2, + MUX_ENABLE_BUS2, + MUX_STAT_BUS2, + CMU_BUS_COMMON_CLK_REGS, +}; + +static struct samsung_div_clock bus0_div_clks[] __initdata = { + /* DIV_BUS0 */ + DIV(CLK_DIV_PCLK_BUS_133, "div_pclk_bus0_133", "aclk_bus0_400", + DIV_BUS, 0, 3), +}; + +/* CMU_BUS0 clocks */ +static struct samsung_gate_clock bus0_gate_clks[] __initdata = { + /* ENABLE_ACLK_BUS0 */ + GATE(CLK_ACLK_AHB2APB_BUSP, "aclk_ahb2apb_bus0p", "div_pclk_bus0_133", + ENABLE_ACLK_BUS, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSNP_133, "aclk_bus0np_133", "div_pclk_bus0_133", + ENABLE_ACLK_BUS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSND_400, "aclk_bus0nd_400", "aclk_bus0_400", + ENABLE_ACLK_BUS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_BUS0 */ + GATE(CLK_PCLK_BUSSRVND_133, "pclk_bus0srvnd_133", "div_pclk_bus0_133", + ENABLE_PCLK_BUS, 2, 0, 0), + GATE(CLK_PCLK_PMU_BUS, "pclk_pmu_bus0", "div_pclk_bus0_133", + ENABLE_PCLK_BUS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_BUS, "pclk_sysreg_bus0", "div_pclk_bus0_133", + ENABLE_PCLK_BUS, 0, CLK_IGNORE_UNUSED, 0), +}; + +/* CMU_BUS1 clocks */ +static struct samsung_div_clock bus1_div_clks[] __initdata = { + /* DIV_BUS1 */ + DIV(CLK_DIV_PCLK_BUS_133, "div_pclk_bus1_133", "aclk_bus1_400", + DIV_BUS, 0, 3), +}; + +static struct samsung_gate_clock bus1_gate_clks[] __initdata = { + /* ENABLE_ACLK_BUS1 */ + GATE(CLK_ACLK_AHB2APB_BUSP, "aclk_ahb2apb_bus1p", "div_pclk_bus1_133", + ENABLE_ACLK_BUS, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSNP_133, "aclk_bus1np_133", "div_pclk_bus1_133", + ENABLE_ACLK_BUS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSND_400, "aclk_bus1nd_400", "aclk_bus1_400", + ENABLE_ACLK_BUS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_BUS1 */ + GATE(CLK_PCLK_BUSSRVND_133, "pclk_bus1srvnd_133", "div_pclk_bus1_133", + ENABLE_PCLK_BUS, 2, 0, 0), + GATE(CLK_PCLK_PMU_BUS, "pclk_pmu_bus1", "div_pclk_bus1_133", + ENABLE_PCLK_BUS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_BUS, "pclk_sysreg_bus1", "div_pclk_bus1_133", + ENABLE_PCLK_BUS, 0, CLK_IGNORE_UNUSED, 0), +}; + +/* CMU_BUS2 clocks */ +static struct samsung_mux_clock bus2_mux_clks[] __initdata = { + /* MUX_SEL_BUS2 */ + MUX(CLK_MOUT_ACLK_BUS2_400_USER, "mout_aclk_bus2_400_user", + mout_aclk_bus2_400_p, MUX_SEL_BUS2, 0, 1), +}; + +static struct samsung_div_clock bus2_div_clks[] __initdata = { + /* DIV_BUS2 */ + DIV(CLK_DIV_PCLK_BUS_133, "div_pclk_bus2_133", + "mout_aclk_bus2_400_user", DIV_BUS, 0, 3), +}; + +static struct samsung_gate_clock bus2_gate_clks[] __initdata = { + /* ENABLE_ACLK_BUS2 */ + GATE(CLK_ACLK_AHB2APB_BUSP, "aclk_ahb2apb_bus2p", "div_pclk_bus2_133", + ENABLE_ACLK_BUS, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSNP_133, "aclk_bus2np_133", "div_pclk_bus2_133", + ENABLE_ACLK_BUS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUS2BEND_400, "aclk_bus2bend_400", + "mout_aclk_bus2_400_user", ENABLE_ACLK_BUS, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUS2RTND_400, "aclk_bus2rtnd_400", + "mout_aclk_bus2_400_user", ENABLE_ACLK_BUS, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_BUS2 */ + GATE(CLK_PCLK_BUSSRVND_133, "pclk_bus2srvnd_133", "div_pclk_bus2_133", + ENABLE_PCLK_BUS, 2, 0, 0), + GATE(CLK_PCLK_PMU_BUS, "pclk_pmu_bus2", "div_pclk_bus2_133", + ENABLE_PCLK_BUS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_BUS, "pclk_sysreg_bus2", "div_pclk_bus2_133", + ENABLE_PCLK_BUS, 0, CLK_IGNORE_UNUSED, 0), +}; + +#define CMU_BUS_INFO_CLKS(id) \ + .div_clks = bus##id##_div_clks, \ + .nr_div_clks = ARRAY_SIZE(bus##id##_div_clks), \ + .gate_clks = bus##id##_gate_clks, \ + .nr_gate_clks = ARRAY_SIZE(bus##id##_gate_clks), \ + .nr_clk_ids = BUSx_NR_CLK + +static struct samsung_cmu_info bus0_cmu_info __initdata = { + CMU_BUS_INFO_CLKS(0), + .clk_regs = bus01_clk_regs, + .nr_clk_regs = ARRAY_SIZE(bus01_clk_regs), +}; + +static struct samsung_cmu_info bus1_cmu_info __initdata = { + CMU_BUS_INFO_CLKS(1), + .clk_regs = bus01_clk_regs, + .nr_clk_regs = ARRAY_SIZE(bus01_clk_regs), +}; + +static struct samsung_cmu_info bus2_cmu_info __initdata = { + CMU_BUS_INFO_CLKS(2), + .mux_clks = bus2_mux_clks, + .nr_mux_clks = ARRAY_SIZE(bus2_mux_clks), + .clk_regs = bus2_clk_regs, + .nr_clk_regs = ARRAY_SIZE(bus2_clk_regs), +}; + +#define exynos5433_cmu_bus_init(id) \ +static void __init exynos5433_cmu_bus##id##_init(struct device_node *np)\ +{ \ + samsung_cmu_register_one(np, &bus##id##_cmu_info); \ +} \ +CLK_OF_DECLARE(exynos5433_cmu_bus##id, \ + "samsung,exynos5433-cmu-bus"#id, \ + exynos5433_cmu_bus##id##_init) + +exynos5433_cmu_bus_init(0); +exynos5433_cmu_bus_init(1); +exynos5433_cmu_bus_init(2); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 4d150e244057..8d388e700a80 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -107,6 +107,9 @@ #define CLK_DIV_ACLK_MFC_400 134 #define CLK_DIV_ACLK_G2D_266 135 #define CLK_DIV_ACLK_G2D_400 136 +#define CLK_DIV_ACLK_G3D_400 137 +#define CLK_DIV_ACLK_BUS0_400 138 +#define CLK_DIV_ACLK_BUS1_400 139 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -130,8 +133,14 @@ #define CLK_SCLK_AUDIO0 219 #define CLK_ACLK_G2D_266 220 #define CLK_ACLK_G2D_400 221 +#define CLK_ACLK_G3D_400 222 +#define CLK_ACLK_IMEM_SSX_266 223 +#define CLK_ACLK_BUS0_400 224 +#define CLK_ACLK_BUS1_400 225 +#define CLK_ACLK_IMEM_200 226 +#define CLK_ACLK_IMEM_266 227 -#define TOP_NR_CLK 222 +#define TOP_NR_CLK 228 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -679,4 +688,20 @@ #define AUD_NR_CLK 48 +/* CMU_BUS{0|1|2} */ +#define CLK_DIV_PCLK_BUS_133 1 + +#define CLK_ACLK_AHB2APB_BUSP 2 +#define CLK_ACLK_BUSNP_133 3 +#define CLK_ACLK_BUSND_400 4 +#define CLK_PCLK_BUSSRVND_133 5 +#define CLK_PCLK_PMU_BUS 6 +#define CLK_PCLK_SYSREG_BUS 7 + +#define CLK_MOUT_ACLK_BUS2_400_USER 8 /* Only CMU_BUS2 */ +#define CLK_ACLK_BUS2BEND_400 9 /* Only CMU_BUS2 */ +#define CLK_ACLK_BUS2RTND_400 10 /* Only CMU_BUS2 */ + +#define BUSx_NR_CLK 11 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 4b8013554b0454984e71bc20bc31966886079e15 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:05 +0900 Subject: clk: samsung: exynos5433: Add missing clocks for CMU_FSYS domain This patch adds the mux/divider/gate clocks for CMU_FSYS domain which contains the clocks of USB/UFS/SDMMC/TSI/PDMA IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 302 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 96 ++++++++++- 2 files changed, 395 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 7c4e91a440e5..1cdc47e05ac1 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -462,6 +462,16 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_SCLK_MMC2_A, "div_sclk_mmc2_a", "mout_sclk_mmc2_b", DIV_TOP_FSYS1, 0, 4), + /* DIV_TOP_FSYS2 */ + DIV(CLK_DIV_SCLK_PCIE_100, "div_sclk_pcie_100", "mout_sclk_pcie_100", + DIV_TOP_FSYS2, 12, 3), + DIV(CLK_DIV_SCLK_USBHOST30, "div_sclk_usbhost30", + "mout_sclk_usbhost30", DIV_TOP_FSYS2, 8, 4), + DIV(CLK_DIV_SCLK_UFSUNIPRO, "div_sclk_ufsunipro", + "mout_sclk_ufsunipro", DIV_TOP_FSYS2, 4, 4), + DIV(CLK_DIV_SCLK_USBDRD30, "div_sclk_usbdrd30", "mout_sclk_usbdrd30", + DIV_TOP_FSYS2, 0, 4), + /* DIV_TOP_PERIC0 */ DIV(CLK_DIV_SCLK_SPI1_B, "div_sclk_spi1_b", "div_sclk_spi1_a", DIV_TOP_PERIC0, 16, 8), @@ -543,12 +553,23 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), /* ENABLE_SCLK_TOP_FSYS */ + GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", + ENABLE_SCLK_TOP_FSYS, 7, 0, 0), GATE(CLK_SCLK_MMC2_FSYS, "sclk_mmc2_fsys", "div_sclk_mmc2_b", ENABLE_SCLK_TOP_FSYS, 6, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC1_FSYS, "sclk_mmc1_fsys", "div_sclk_mmc1_b", ENABLE_SCLK_TOP_FSYS, 5, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC0_FSYS, "sclk_mmc0_fsys", "div_sclk_mmc0_b", ENABLE_SCLK_TOP_FSYS, 4, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UFSUNIPRO_FSYS, "sclk_ufsunipro_fsys", + "div_sclk_ufsunipro", ENABLE_SCLK_TOP_FSYS, + 3, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_USBHOST30_FSYS, "sclk_usbhost30_fsys", + "div_sclk_usbhost30", ENABLE_SCLK_TOP_FSYS, + 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_USBDRD30_FSYS, "sclk_usbdrd30_fsys", + "div_sclk_usbdrd30", ENABLE_SCLK_TOP_FSYS, + 0, CLK_SET_RATE_PARENT, 0), /* ENABLE_SCLK_TOP_PERIC */ GATE(CLK_SCLK_SPI4_PERIC, "sclk_spi4_peric", "div_sclk_spi4_b", @@ -1832,10 +1853,45 @@ CLK_OF_DECLARE(exynos5433_cmu_peris, "samsung,exynos5433-cmu-peris", #define ENABLE_IP_FSYS1 0x0b04 /* list of all parent clock list */ +PNAME(mout_sclk_ufs_mphy_user_p) = { "oscclk", "sclk_ufs_mphy", }; PNAME(mout_aclk_fsys_200_user_p) = { "oscclk", "div_aclk_fsys_200", }; +PNAME(mout_sclk_pcie_100_user_p) = { "oscclk", "sclk_pcie_100_fsys",}; +PNAME(mout_sclk_ufsunipro_user_p) = { "oscclk", "sclk_ufsunipro_fsys",}; PNAME(mout_sclk_mmc2_user_p) = { "oscclk", "sclk_mmc2_fsys", }; PNAME(mout_sclk_mmc1_user_p) = { "oscclk", "sclk_mmc1_fsys", }; PNAME(mout_sclk_mmc0_user_p) = { "oscclk", "sclk_mmc0_fsys", }; +PNAME(mout_sclk_usbhost30_user_p) = { "oscclk", "sclk_usbhost30_fsys",}; +PNAME(mout_sclk_usbdrd30_user_p) = { "oscclk", "sclk_usbdrd30_fsys", }; + +PNAME(mout_phyclk_usbhost30_uhost30_pipe_pclk_user_p) + = { "oscclk", "phyclk_usbhost30_uhost30_pipe_pclk_phy", }; +PNAME(mout_phyclk_usbhost30_uhost30_phyclock_user_p) + = { "oscclk", "phyclk_usbhost30_uhost30_phyclock_phy", }; +PNAME(mout_phyclk_usbhost20_phy_hsic1_p) + = { "oscclk", "phyclk_usbhost20_phy_hsic1_phy", }; +PNAME(mout_phyclk_usbhost20_phy_clk48mohci_user_p) + = { "oscclk", "phyclk_usbhost20_phy_clk48mohci_phy", }; +PNAME(mout_phyclk_usbhost20_phy_phyclock_user_p) + = { "oscclk", "phyclk_usbhost20_phy_phyclock_phy", }; +PNAME(mout_phyclk_usbhost20_phy_freeclk_user_p) + = { "oscclk", "phyclk_usbhost20_phy_freeclk_phy", }; +PNAME(mout_phyclk_usbdrd30_udrd30_pipe_pclk_p) + = { "oscclk", "phyclk_usbdrd30_udrd30_pipe_pclk_phy", }; +PNAME(mout_phyclk_usbdrd30_udrd30_phyclock_user_p) + = { "oscclk", "phyclk_usbdrd30_udrd30_phyclock_phy", }; +PNAME(mout_phyclk_ufs_rx1_symbol_user_p) + = { "oscclk", "phyclk_ufs_rx1_symbol_phy", }; +PNAME(mout_phyclk_ufs_rx0_symbol_user_p) + = { "oscclk", "phyclk_ufs_rx0_symbol_phy", }; +PNAME(mout_phyclk_ufs_tx1_symbol_user_p) + = { "oscclk", "phyclk_ufs_tx1_symbol_phy", }; +PNAME(mout_phyclk_ufs_tx0_symbol_user_p) + = { "oscclk", "phyclk_ufs_tx0_symbol_phy", }; +PNAME(mout_phyclk_lli_mphy_to_ufs_user_p) + = { "oscclk", "phyclk_lli_mphy_to_ufs_phy", }; +PNAME(mout_sclk_mphy_p) + = { "mout_sclk_ufs_mphy_user", + "mout_phyclk_lli_mphy_to_ufs_user", }; static unsigned long fsys_clk_regs[] __initdata = { MUX_SEL_FSYS0, @@ -1863,18 +1919,130 @@ static unsigned long fsys_clk_regs[] __initdata = { ENABLE_IP_FSYS1, }; +static struct samsung_fixed_rate_clock fsys_fixed_clks[] __initdata = { + /* PHY clocks from USBDRD30_PHY */ + FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY, + "phyclk_usbdrd30_udrd30_phyclock_phy", NULL, + CLK_IS_ROOT, 60000000), + FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_PHY, + "phyclk_usbdrd30_udrd30_pipe_pclk_phy", NULL, + CLK_IS_ROOT, 125000000), + /* PHY clocks from USBHOST30_PHY */ + FRATE(CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_PHY, + "phyclk_usbhost30_uhost30_phyclock_phy", NULL, + CLK_IS_ROOT, 60000000), + FRATE(CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_PHY, + "phyclk_usbhost30_uhost30_pipe_pclk_phy", NULL, + CLK_IS_ROOT, 125000000), + /* PHY clocks from USBHOST20_PHY */ + FRATE(CLK_PHYCLK_USBHOST20_PHY_FREECLK_PHY, + "phyclk_usbhost20_phy_freeclk_phy", NULL, CLK_IS_ROOT, + 60000000), + FRATE(CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK_PHY, + "phyclk_usbhost20_phy_phyclock_phy", NULL, CLK_IS_ROOT, + 60000000), + FRATE(CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI_PHY, + "phyclk_usbhost20_phy_clk48mohci_phy", NULL, + CLK_IS_ROOT, 48000000), + FRATE(CLK_PHYCLK_USBHOST20_PHY_HSIC1_PHY, + "phyclk_usbhost20_phy_hsic1_phy", NULL, CLK_IS_ROOT, + 60000000), + /* PHY clocks from UFS_PHY */ + FRATE(CLK_PHYCLK_UFS_TX0_SYMBOL_PHY, "phyclk_ufs_tx0_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + FRATE(CLK_PHYCLK_UFS_RX0_SYMBOL_PHY, "phyclk_ufs_rx0_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + FRATE(CLK_PHYCLK_UFS_TX1_SYMBOL_PHY, "phyclk_ufs_tx1_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + FRATE(CLK_PHYCLK_UFS_RX1_SYMBOL_PHY, "phyclk_ufs_rx1_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + /* PHY clocks from LLI_PHY */ + FRATE(CLK_PHYCLK_LLI_MPHY_TO_UFS_PHY, "phyclk_lli_mphy_to_ufs_phy", + NULL, CLK_IS_ROOT, 26000000), +}; + static struct samsung_mux_clock fsys_mux_clks[] __initdata = { /* MUX_SEL_FSYS0 */ + MUX(CLK_MOUT_SCLK_UFS_MPHY_USER, "mout_sclk_ufs_mphy_user", + mout_sclk_ufs_mphy_user_p, MUX_SEL_FSYS0, 4, 1), MUX(CLK_MOUT_ACLK_FSYS_200_USER, "mout_aclk_fsys_200_user", mout_aclk_fsys_200_user_p, MUX_SEL_FSYS0, 0, 1), /* MUX_SEL_FSYS1 */ + MUX(CLK_MOUT_SCLK_PCIE_100_USER, "mout_sclk_pcie_100_user", + mout_sclk_pcie_100_user_p, MUX_SEL_FSYS1, 28, 1), + MUX(CLK_MOUT_SCLK_UFSUNIPRO_USER, "mout_sclk_ufsunipro_user", + mout_sclk_ufsunipro_user_p, MUX_SEL_FSYS1, 24, 1), MUX(CLK_MOUT_SCLK_MMC2_USER, "mout_sclk_mmc2_user", mout_sclk_mmc2_user_p, MUX_SEL_FSYS1, 20, 1), MUX(CLK_MOUT_SCLK_MMC1_USER, "mout_sclk_mmc1_user", mout_sclk_mmc1_user_p, MUX_SEL_FSYS1, 16, 1), MUX(CLK_MOUT_SCLK_MMC0_USER, "mout_sclk_mmc0_user", mout_sclk_mmc0_user_p, MUX_SEL_FSYS1, 12, 1), + MUX(CLK_MOUT_SCLK_USBHOST30_USER, "mout_sclk_usbhost30_user", + mout_sclk_usbhost30_user_p, MUX_SEL_FSYS1, 4, 1), + MUX(CLK_MOUT_SCLK_USBDRD30_USER, "mout_sclk_usbdrd30_user", + mout_sclk_usbdrd30_user_p, MUX_SEL_FSYS1, 0, 1), + + /* MUX_SEL_FSYS2 */ + MUX(CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_USER, + "mout_phyclk_usbhost30_uhost30_pipe_pclk_user", + mout_phyclk_usbhost30_uhost30_pipe_pclk_user_p, + MUX_SEL_FSYS2, 28, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_USER, + "mout_phyclk_usbhost30_uhost30_phyclock_user", + mout_phyclk_usbhost30_uhost30_phyclock_user_p, + MUX_SEL_FSYS2, 24, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_HSIC1_USER, + "mout_phyclk_usbhost20_phy_hsic1", + mout_phyclk_usbhost20_phy_hsic1_p, + MUX_SEL_FSYS2, 20, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_CLK48MOHCI_USER, + "mout_phyclk_usbhost20_phy_clk48mohci_user", + mout_phyclk_usbhost20_phy_clk48mohci_user_p, + MUX_SEL_FSYS2, 16, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_PHYCLOCK_USER, + "mout_phyclk_usbhost20_phy_phyclock_user", + mout_phyclk_usbhost20_phy_phyclock_user_p, + MUX_SEL_FSYS2, 12, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_PHY_FREECLK_USER, + "mout_phyclk_usbhost20_phy_freeclk_user", + mout_phyclk_usbhost20_phy_freeclk_user_p, + MUX_SEL_FSYS2, 8, 1), + MUX(CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_USER, + "mout_phyclk_usbdrd30_udrd30_pipe_pclk_user", + mout_phyclk_usbdrd30_udrd30_pipe_pclk_p, + MUX_SEL_FSYS2, 4, 1), + MUX(CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_USER, + "mout_phyclk_usbdrd30_udrd30_phyclock_user", + mout_phyclk_usbdrd30_udrd30_phyclock_user_p, + MUX_SEL_FSYS2, 0, 1), + + /* MUX_SEL_FSYS3 */ + MUX(CLK_MOUT_PHYCLK_UFS_RX1_SYMBOL_USER, + "mout_phyclk_ufs_rx1_symbol_user", + mout_phyclk_ufs_rx1_symbol_user_p, + MUX_SEL_FSYS3, 16, 1), + MUX(CLK_MOUT_PHYCLK_UFS_RX0_SYMBOL_USER, + "mout_phyclk_ufs_rx0_symbol_user", + mout_phyclk_ufs_rx0_symbol_user_p, + MUX_SEL_FSYS3, 12, 1), + MUX(CLK_MOUT_PHYCLK_UFS_TX1_SYMBOL_USER, + "mout_phyclk_ufs_tx1_symbol_user", + mout_phyclk_ufs_tx1_symbol_user_p, + MUX_SEL_FSYS3, 8, 1), + MUX(CLK_MOUT_PHYCLK_UFS_TX0_SYMBOL_USER, + "mout_phyclk_ufs_tx0_symbol_user", + mout_phyclk_ufs_tx0_symbol_user_p, + MUX_SEL_FSYS3, 4, 1), + MUX(CLK_MOUT_PHYCLK_LLI_MPHY_TO_UFS_USER, + "mout_phyclk_lli_mphy_to_ufs_user", + mout_phyclk_lli_mphy_to_ufs_user_p, + MUX_SEL_FSYS3, 0, 1), + + /* MUX_SEL_FSYS4 */ + MUX(CLK_MOUT_SCLK_MPHY, "mout_sclk_mphy", mout_sclk_mphy_p, + MUX_SEL_FSYS4, 0, 1), }; static struct samsung_gate_clock fsys_gate_clks[] __initdata = { @@ -1902,13 +2070,145 @@ static struct samsung_gate_clock fsys_gate_clks[] __initdata = { GATE(CLK_ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS0, 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_ACLK_FSYS1 */ + GATE(CLK_ACLK_XIU_FSYSPX, "aclk_xiu_fsyspx", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_USBLINKH1, "aclk_ahb_usblinkh1", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_PDMA1, "aclk_smmu_pdma1", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_PCIE, "aclk_bts_pcie", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 24, 0, 0), + GATE(CLK_ACLK_AXIUS_PDMA1, "aclk_axius_pdma1", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_PDMA0, "aclk_smmu_pdma0", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_UFS, "aclk_bts_ufs", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_USBHOST30, "aclk_bts_usbhost30", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 13, 0, 0), + GATE(CLK_ACLK_BTS_USBDRD30, "aclk_bts_usbdrd30", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 12, 0, 0), + GATE(CLK_ACLK_AXIUS_PDMA0, "aclk_axius_pdma0", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_USBHS, "aclk_axius_usbhs", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_FSYSSX, "aclk_axius_fsyssx", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_FSYSP, "aclk_ahb2apb_fsysp", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2AXI_USBHS, "aclk_ahb2axi_usbhs", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_USBLINKH0, "aclk_ahb_usblinkh0", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_USBHS, "aclk_ahb_usbhs", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_FSYSH, "aclk_ahb_fsysh", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_FSYSX, "aclk_xiu_fsysx", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_FSYSSX, "aclk_xiu_fsyssx", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_FSYSNP_200, "aclk_fsysnp_200", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_FSYSND_200, "aclk_fsysnd_200", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_FSYS */ + GATE(CLK_PCLK_PCIE_CTRL, "pclk_pcie_ctrl", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 17, 0, 0), + GATE(CLK_PCLK_SMMU_PDMA1, "pclk_smmu_pdma1", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PCIE_PHY, "pclk_pcie_phy", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 14, 0, 0), + GATE(CLK_PCLK_BTS_PCIE, "pclk_bts_pcie", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 13, 0, 0), + GATE(CLK_PCLK_SMMU_PDMA0, "pclk_smmu_pdma0", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_UFS, "pclk_bts_ufs", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 5, 0, 0), + GATE(CLK_PCLK_BTS_USBHOST30, "pclk_bts_usbhost30", + "mout_aclk_fsys_200_user", ENABLE_PCLK_FSYS, 4, 0, 0), + GATE(CLK_PCLK_BTS_USBDRD30, "pclk_bts_usbdrd30", + "mout_aclk_fsys_200_user", ENABLE_PCLK_FSYS, 3, 0, 0), + GATE(CLK_PCLK_GPIO_FSYS, "pclk_gpio_fsys", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_FSYS, "pclk_pmu_fsys", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_FSYS, "pclk_sysreg_fsys", + "mout_aclk_fsys_200_user", ENABLE_PCLK_FSYS, + 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_SCLK_FSYS */ + GATE(CLK_SCLK_PCIE_100, "sclk_pcie_100", "mout_sclk_pcie_100_user", + ENABLE_SCLK_FSYS, 21, 0, 0), + GATE(CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK, + "phyclk_usbhost30_uhost30_pipe_pclk", + "mout_phyclk_usbhost30_uhost30_pipe_pclk_user", + ENABLE_SCLK_FSYS, 18, 0, 0), + GATE(CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK, + "phyclk_usbhost30_uhost30_phyclock", + "mout_phyclk_usbhost30_uhost30_phyclock_user", + ENABLE_SCLK_FSYS, 17, 0, 0), + GATE(CLK_PHYCLK_UFS_RX1_SYMBOL, "phyclk_ufs_rx1_symbol", + "mout_phyclk_ufs_rx1_symbol_user", ENABLE_SCLK_FSYS, + 16, 0, 0), + GATE(CLK_PHYCLK_UFS_RX0_SYMBOL, "phyclk_ufs_rx0_symbol", + "mout_phyclk_ufs_rx0_symbol_user", ENABLE_SCLK_FSYS, + 15, 0, 0), + GATE(CLK_PHYCLK_UFS_TX1_SYMBOL, "phyclk_ufs_tx1_symbol", + "mout_phyclk_ufs_tx1_symbol_user", ENABLE_SCLK_FSYS, + 14, 0, 0), + GATE(CLK_PHYCLK_UFS_TX0_SYMBOL, "phyclk_ufs_tx0_symbol", + "mout_phyclk_ufs_tx0_symbol_user", ENABLE_SCLK_FSYS, + 13, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_HSIC1, "phyclk_usbhost20_phy_hsic1", + "mout_phyclk_usbhost20_phy_hsic1", ENABLE_SCLK_FSYS, + 12, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI, + "phyclk_usbhost20_phy_clk48mohci", + "mout_phyclk_usbhost20_phy_clk48mohci_user", + ENABLE_SCLK_FSYS, 11, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK, + "phyclk_usbhost20_phy_phyclock", + "mout_phyclk_usbhost20_phy_phyclock_user", + ENABLE_SCLK_FSYS, 10, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_FREECLK, + "phyclk_usbhost20_phy_freeclk", + "mout_phyclk_usbhost20_phy_freeclk_user", + ENABLE_SCLK_FSYS, 9, 0, 0), + GATE(CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK, + "phyclk_usbdrd30_udrd30_pipe_pclk", + "mout_phyclk_usbdrd30_udrd30_pipe_pclk_user", + ENABLE_SCLK_FSYS, 8, 0, 0), + GATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK, + "phyclk_usbdrd30_udrd30_phyclock", + "mout_phyclk_usbdrd30_udrd30_phyclock_user", + ENABLE_SCLK_FSYS, 7, 0, 0), + GATE(CLK_SCLK_MPHY, "sclk_mphy", "mout_sclk_mphy", + ENABLE_SCLK_FSYS, 6, 0, 0), + GATE(CLK_SCLK_UFSUNIPRO, "sclk_ufsunipro", "mout_sclk_ufsunipro_user", + ENABLE_SCLK_FSYS, 5, 0, 0), GATE(CLK_SCLK_MMC2, "sclk_mmc2", "mout_sclk_mmc2_user", ENABLE_SCLK_FSYS, 4, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC1, "sclk_mmc1", "mout_sclk_mmc1_user", ENABLE_SCLK_FSYS, 3, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC0, "sclk_mmc0", "mout_sclk_mmc0_user", ENABLE_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_USBHOST30, "sclk_usbhost30", "mout_sclk_usbhost30_user", + ENABLE_SCLK_FSYS, 1, 0, 0), + GATE(CLK_SCLK_USBDRD30, "sclk_usbdrd30", "mout_sclk_usbdrd30_user", + ENABLE_SCLK_FSYS, 0, 0, 0), /* ENABLE_IP_FSYS0 */ GATE(CLK_PDMA1, "pdma1", "aclk_pdma1", ENABLE_IP_FSYS0, 15, 0, 0), @@ -1920,6 +2220,8 @@ static struct samsung_cmu_info fsys_cmu_info __initdata = { .nr_mux_clks = ARRAY_SIZE(fsys_mux_clks), .gate_clks = fsys_gate_clks, .nr_gate_clks = ARRAY_SIZE(fsys_gate_clks), + .fixed_clks = fsys_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(fsys_fixed_clks), .nr_clk_ids = FSYS_NR_CLK, .clk_regs = fsys_clk_regs, .nr_clk_regs = ARRAY_SIZE(fsys_clk_regs), diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 8d388e700a80..294a2d0a67ff 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -110,6 +110,10 @@ #define CLK_DIV_ACLK_G3D_400 137 #define CLK_DIV_ACLK_BUS0_400 138 #define CLK_DIV_ACLK_BUS1_400 139 +#define CLK_DIV_SCLK_PCIE_100 140 +#define CLK_DIV_SCLK_USBHOST30 141 +#define CLK_DIV_SCLK_UFSUNIPRO 142 +#define CLK_DIV_SCLK_USBDRD30 143 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -139,8 +143,12 @@ #define CLK_ACLK_BUS1_400 225 #define CLK_ACLK_IMEM_200 226 #define CLK_ACLK_IMEM_266 227 +#define CLK_SCLK_PCIE_100_FSYS 228 +#define CLK_SCLK_UFSUNIPRO_FSYS 229 +#define CLK_SCLK_USBHOST30_FSYS 230 +#define CLK_SCLK_USBDRD30_FSYS 231 -#define TOP_NR_CLK 228 +#define TOP_NR_CLK 232 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -473,6 +481,39 @@ #define CLK_MOUT_SCLK_MMC2_USER 2 #define CLK_MOUT_SCLK_MMC1_USER 3 #define CLK_MOUT_SCLK_MMC0_USER 4 +#define CLK_MOUT_SCLK_UFS_MPHY_USER 5 +#define CLK_MOUT_SCLK_PCIE_100_USER 6 +#define CLK_MOUT_SCLK_UFSUNIPRO_USER 7 +#define CLK_MOUT_SCLK_USBHOST30_USER 8 +#define CLK_MOUT_SCLK_USBDRD30_USER 9 +#define CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_USER 10 +#define CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_USER 11 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_HSIC1_USER 12 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_CLK48MOHCI_USER 13 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_PHYCLOCK_USER 14 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_PHY_FREECLK_USER 15 +#define CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_USER 16 +#define CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_USER 17 +#define CLK_MOUT_PHYCLK_UFS_RX1_SYMBOL_USER 18 +#define CLK_MOUT_PHYCLK_UFS_RX0_SYMBOL_USER 19 +#define CLK_MOUT_PHYCLK_UFS_TX1_SYMBOL_USER 20 +#define CLK_MOUT_PHYCLK_UFS_TX0_SYMBOL_USER 21 +#define CLK_MOUT_PHYCLK_LLI_MPHY_TO_UFS_USER 22 +#define CLK_MOUT_SCLK_MPHY 23 + +#define CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY 25 +#define CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_PHY 26 +#define CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_PHY 27 +#define CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_PHY 28 +#define CLK_PHYCLK_USBHOST20_PHY_FREECLK_PHY 29 +#define CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK_PHY 30 +#define CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI_PHY 31 +#define CLK_PHYCLK_USBHOST20_PHY_HSIC1_PHY 32 +#define CLK_PHYCLK_UFS_TX0_SYMBOL_PHY 33 +#define CLK_PHYCLK_UFS_RX0_SYMBOL_PHY 34 +#define CLK_PHYCLK_UFS_TX1_SYMBOL_PHY 35 +#define CLK_PHYCLK_UFS_RX1_SYMBOL_PHY 36 +#define CLK_PHYCLK_LLI_MPHY_TO_UFS_PHY 37 #define CLK_ACLK_PCIE 50 #define CLK_ACLK_PDMA1 51 @@ -490,8 +531,57 @@ #define CLK_SCLK_MMC0 63 #define CLK_PDMA1 64 #define CLK_PDMA0 65 - -#define FSYS_NR_CLK 66 +#define CLK_ACLK_XIU_FSYSPX 66 +#define CLK_ACLK_AHB_USBLINKH1 67 +#define CLK_ACLK_SMMU_PDMA1 68 +#define CLK_ACLK_BTS_PCIE 69 +#define CLK_ACLK_AXIUS_PDMA1 70 +#define CLK_ACLK_SMMU_PDMA0 71 +#define CLK_ACLK_BTS_UFS 72 +#define CLK_ACLK_BTS_USBHOST30 73 +#define CLK_ACLK_BTS_USBDRD30 74 +#define CLK_ACLK_AXIUS_PDMA0 75 +#define CLK_ACLK_AXIUS_USBHS 76 +#define CLK_ACLK_AXIUS_FSYSSX 77 +#define CLK_ACLK_AHB2APB_FSYSP 78 +#define CLK_ACLK_AHB2AXI_USBHS 79 +#define CLK_ACLK_AHB_USBLINKH0 80 +#define CLK_ACLK_AHB_USBHS 81 +#define CLK_ACLK_AHB_FSYSH 82 +#define CLK_ACLK_XIU_FSYSX 83 +#define CLK_ACLK_XIU_FSYSSX 84 +#define CLK_ACLK_FSYSNP_200 85 +#define CLK_ACLK_FSYSND_200 86 +#define CLK_PCLK_PCIE_CTRL 87 +#define CLK_PCLK_SMMU_PDMA1 88 +#define CLK_PCLK_PCIE_PHY 89 +#define CLK_PCLK_BTS_PCIE 90 +#define CLK_PCLK_SMMU_PDMA0 91 +#define CLK_PCLK_BTS_UFS 92 +#define CLK_PCLK_BTS_USBHOST30 93 +#define CLK_PCLK_BTS_USBDRD30 94 +#define CLK_PCLK_GPIO_FSYS 95 +#define CLK_PCLK_PMU_FSYS 96 +#define CLK_PCLK_SYSREG_FSYS 97 +#define CLK_SCLK_PCIE_100 98 +#define CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK 99 +#define CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK 100 +#define CLK_PHYCLK_UFS_RX1_SYMBOL 101 +#define CLK_PHYCLK_UFS_RX0_SYMBOL 102 +#define CLK_PHYCLK_UFS_TX1_SYMBOL 103 +#define CLK_PHYCLK_UFS_TX0_SYMBOL 104 +#define CLK_PHYCLK_USBHOST20_PHY_HSIC1 105 +#define CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI 106 +#define CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK 107 +#define CLK_PHYCLK_USBHOST20_PHY_FREECLK 108 +#define CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK 109 +#define CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK 110 +#define CLK_SCLK_MPHY 111 +#define CLK_SCLK_UFSUNIPRO 112 +#define CLK_SCLK_USBHOST30 113 +#define CLK_SCLK_USBDRD30 114 + +#define FSYS_NR_CLK 115 /* CMU_G2D */ #define CLK_MUX_ACLK_G2D_266_USER 1 -- cgit v1.2.3 From 453e519e5aed806c1b70bcbe92aeab39a93dda22 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:06 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_G3D domain This patch adds the mux/divider/gate clocks for CMU_G3D domain which contains the clocks for GPU(3D Graphics Engine). Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 127 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 25 +++++++ 2 files changed, 152 insertions(+) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 1cdc47e05ac1..f422485a92c0 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3120,3 +3120,130 @@ CLK_OF_DECLARE(exynos5433_cmu_bus##id, \ exynos5433_cmu_bus_init(0); exynos5433_cmu_bus_init(1); exynos5433_cmu_bus_init(2); + +/* + * Register offset definitions for CMU_G3D + */ +#define G3D_PLL_LOCK 0x0000 +#define G3D_PLL_CON0 0x0100 +#define G3D_PLL_CON1 0x0104 +#define G3D_PLL_FREQ_DET 0x010c +#define MUX_SEL_G3D 0x0200 +#define MUX_ENABLE_G3D 0x0300 +#define MUX_STAT_G3D 0x0400 +#define DIV_G3D 0x0600 +#define DIV_G3D_PLL_FREQ_DET 0x0604 +#define DIV_STAT_G3D 0x0700 +#define DIV_STAT_G3D_PLL_FREQ_DET 0x0704 +#define ENABLE_ACLK_G3D 0x0800 +#define ENABLE_PCLK_G3D 0x0900 +#define ENABLE_SCLK_G3D 0x0a00 +#define ENABLE_IP_G3D0 0x0b00 +#define ENABLE_IP_G3D1 0x0b04 +#define CLKOUT_CMU_G3D 0x0c00 +#define CLKOUT_CMU_G3D_DIV_STAT 0x0c04 +#define CLK_STOPCTRL 0x1000 + +static unsigned long g3d_clk_regs[] __initdata = { + G3D_PLL_LOCK, + G3D_PLL_CON0, + G3D_PLL_CON1, + G3D_PLL_FREQ_DET, + MUX_SEL_G3D, + MUX_ENABLE_G3D, + MUX_STAT_G3D, + DIV_G3D, + DIV_G3D_PLL_FREQ_DET, + DIV_STAT_G3D, + DIV_STAT_G3D_PLL_FREQ_DET, + ENABLE_ACLK_G3D, + ENABLE_PCLK_G3D, + ENABLE_SCLK_G3D, + ENABLE_IP_G3D0, + ENABLE_IP_G3D1, + CLKOUT_CMU_G3D, + CLKOUT_CMU_G3D_DIV_STAT, + CLK_STOPCTRL, +}; + +/* list of all parent clock list */ +PNAME(mout_aclk_g3d_400_p) = { "mout_g3d_pll", "aclk_g3d_400", }; +PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll", }; + +static struct samsung_pll_clock g3d_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "oscclk", + G3D_PLL_LOCK, G3D_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_mux_clock g3d_mux_clks[] __initdata = { + /* MUX_SEL_G3D */ + MUX(CLK_MOUT_ACLK_G3D_400, "mout_aclk_g3d_400", mout_aclk_g3d_400_p, + MUX_SEL_G3D, 8, 1), + MUX(CLK_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p, + MUX_SEL_G3D, 0, 1), +}; + +static struct samsung_div_clock g3d_div_clks[] __initdata = { + /* DIV_G3D */ + DIV(CLK_DIV_SCLK_HPM_G3D, "div_sclk_hpm_g3d", "mout_g3d_pll", DIV_G3D, + 8, 2), + DIV(CLK_DIV_PCLK_G3D, "div_pclk_g3d", "div_aclk_g3d", DIV_G3D, + 4, 3), + DIV(CLK_DIV_ACLK_G3D, "div_aclk_g3d", "mout_aclk_g3d_400", DIV_G3D, + 0, 3), +}; + +static struct samsung_gate_clock g3d_gate_clks[] __initdata = { + /* ENABLE_ACLK_G3D */ + GATE(CLK_ACLK_BTS_G3D1, "aclk_bts_g3d1", "div_aclk_g3d", + ENABLE_ACLK_G3D, 7, 0, 0), + GATE(CLK_ACLK_BTS_G3D0, "aclk_bts_g3d0", "div_aclk_g3d", + ENABLE_ACLK_G3D, 6, 0, 0), + GATE(CLK_ACLK_ASYNCAPBS_G3D, "aclk_asyncapbs_g3d", "div_pclk_g3d", + ENABLE_ACLK_G3D, 5, 0, 0), + GATE(CLK_ACLK_ASYNCAPBM_G3D, "aclk_asyncapbm_g3d", "div_aclk_g3d", + ENABLE_ACLK_G3D, 4, 0, 0), + GATE(CLK_ACLK_AHB2APB_G3DP, "aclk_ahb2apb_g3dp", "div_pclk_g3d", + ENABLE_ACLK_G3D, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G3DNP_150, "aclk_g3dnp_150", "div_pclk_g3d", + ENABLE_ACLK_G3D, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G3DND_600, "aclk_g3dnd_600", "div_aclk_g3d", + ENABLE_ACLK_G3D, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G3D, "aclk_g3d", "div_aclk_g3d", + ENABLE_ACLK_G3D, 0, 0, 0), + + /* ENABLE_PCLK_G3D */ + GATE(CLK_PCLK_BTS_G3D1, "pclk_bts_g3d1", "div_pclk_g3d", + ENABLE_PCLK_G3D, 3, 0, 0), + GATE(CLK_PCLK_BTS_G3D0, "pclk_bts_g3d0", "div_pclk_g3d", + ENABLE_PCLK_G3D, 2, 0, 0), + GATE(CLK_PCLK_PMU_G3D, "pclk_pmu_g3d", "div_pclk_g3d", + ENABLE_PCLK_G3D, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_G3D, "pclk_sysreg_g3d", "div_pclk_g3d", + ENABLE_PCLK_G3D, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_G3D */ + GATE(CLK_SCLK_HPM_G3D, "sclk_hpm_g3d", "div_sclk_hpm_g3d", + ENABLE_SCLK_G3D, 0, 0, 0), +}; + +static struct samsung_cmu_info g3d_cmu_info __initdata = { + .pll_clks = g3d_pll_clks, + .nr_pll_clks = ARRAY_SIZE(g3d_pll_clks), + .mux_clks = g3d_mux_clks, + .nr_mux_clks = ARRAY_SIZE(g3d_mux_clks), + .div_clks = g3d_div_clks, + .nr_div_clks = ARRAY_SIZE(g3d_div_clks), + .gate_clks = g3d_gate_clks, + .nr_gate_clks = ARRAY_SIZE(g3d_gate_clks), + .nr_clk_ids = G3D_NR_CLK, + .clk_regs = g3d_clk_regs, + .nr_clk_regs = ARRAY_SIZE(g3d_clk_regs), +}; + +static void __init exynos5433_cmu_g3d_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &g3d_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d", + exynos5433_cmu_g3d_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 294a2d0a67ff..60ccc169e9ff 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -794,4 +794,29 @@ #define BUSx_NR_CLK 11 +/* CMU_G3D */ +#define CLK_FOUT_G3D_PLL 1 + +#define CLK_MOUT_ACLK_G3D_400 2 +#define CLK_MOUT_G3D_PLL 3 + +#define CLK_DIV_SCLK_HPM_G3D 4 +#define CLK_DIV_PCLK_G3D 5 +#define CLK_DIV_ACLK_G3D 6 +#define CLK_ACLK_BTS_G3D1 7 +#define CLK_ACLK_BTS_G3D0 8 +#define CLK_ACLK_ASYNCAPBS_G3D 9 +#define CLK_ACLK_ASYNCAPBM_G3D 10 +#define CLK_ACLK_AHB2APB_G3DP 11 +#define CLK_ACLK_G3DNP_150 12 +#define CLK_ACLK_G3DND_600 13 +#define CLK_ACLK_G3D 14 +#define CLK_PCLK_BTS_G3D1 15 +#define CLK_PCLK_BTS_G3D0 16 +#define CLK_PCLK_PMU_G3D 17 +#define CLK_PCLK_SYSREG_G3D 18 +#define CLK_SCLK_HPM_G3D 19 + +#define G3D_NR_CLK 20 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 2a2f33e83ddb6c0abe3d32075f795aa14e4b9476 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:07 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_GSCL domain This patch adds the divider/gate of CMU_GSCL domain which contains gscaler clocks. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 146 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 37 ++++++++- 2 files changed, 182 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index f422485a92c0..12f60c6a5a7a 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -545,6 +545,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_FSYS_200, "aclk_fsys_200", "div_aclk_fsys_200", ENABLE_ACLK_TOP, 18, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_GSCL_111, "aclk_gscl_111", "div_aclk_gscl_111", + ENABLE_ACLK_TOP, 15, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", + ENABLE_ACLK_TOP, 14, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_G2D_266, "aclk_g2d_266", "div_aclk_g2d_266", ENABLE_ACLK_TOP, 2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -3247,3 +3253,143 @@ static void __init exynos5433_cmu_g3d_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d", exynos5433_cmu_g3d_init); + +/* + * Register offset definitions for CMU_GSCL + */ +#define MUX_SEL_GSCL 0x0200 +#define MUX_ENABLE_GSCL 0x0300 +#define MUX_STAT_GSCL 0x0400 +#define ENABLE_ACLK_GSCL 0x0800 +#define ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0 0x0804 +#define ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1 0x0808 +#define ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2 0x080c +#define ENABLE_PCLK_GSCL 0x0900 +#define ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0 0x0904 +#define ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1 0x0908 +#define ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2 0x090c +#define ENABLE_IP_GSCL0 0x0b00 +#define ENABLE_IP_GSCL1 0x0b04 +#define ENABLE_IP_GSCL_SECURE_SMMU_GSCL0 0x0b08 +#define ENABLE_IP_GSCL_SECURE_SMMU_GSCL1 0x0b0c +#define ENABLE_IP_GSCL_SECURE_SMMU_GSCL2 0x0b10 + +static unsigned long gscl_clk_regs[] __initdata = { + MUX_SEL_GSCL, + MUX_ENABLE_GSCL, + MUX_STAT_GSCL, + ENABLE_ACLK_GSCL, + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0, + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1, + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2, + ENABLE_PCLK_GSCL, + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1, + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2, + ENABLE_IP_GSCL0, + ENABLE_IP_GSCL1, + ENABLE_IP_GSCL_SECURE_SMMU_GSCL0, + ENABLE_IP_GSCL_SECURE_SMMU_GSCL1, + ENABLE_IP_GSCL_SECURE_SMMU_GSCL2, +}; + +/* list of all parent clock list */ +PNAME(aclk_gscl_111_user_p) = { "oscclk", "aclk_gscl_111", }; +PNAME(aclk_gscl_333_user_p) = { "oscclk", "aclk_gscl_333", }; + +static struct samsung_mux_clock gscl_mux_clks[] __initdata = { + /* MUX_SEL_GSCL */ + MUX(CLK_MOUT_ACLK_GSCL_111_USER, "mout_aclk_gscl_111_user", + aclk_gscl_111_user_p, MUX_SEL_GSCL, 4, 1), + MUX(CLK_MOUT_ACLK_GSCL_333_USER, "mout_aclk_gscl_333_user", + aclk_gscl_333_user_p, MUX_SEL_GSCL, 0, 1), +}; + +static struct samsung_gate_clock gscl_gate_clks[] __initdata = { + /* ENABLE_ACLK_GSCL */ + GATE(CLK_ACLK_BTS_GSCL2, "aclk_bts_gscl2", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 11, 0, 0), + GATE(CLK_ACLK_BTS_GSCL1, "aclk_bts_gscl1", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 10, 0, 0), + GATE(CLK_ACLK_BTS_GSCL0, "aclk_bts_gscl0", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 9, 0, 0), + GATE(CLK_ACLK_AHB2APB_GSCLP, "aclk_ahb2apb_gsclp", + "mout_aclk_gscl_111_user", ENABLE_ACLK_GSCL, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_GSCLX, "aclk_xiu_gsclx", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 7, 0, 0), + GATE(CLK_ACLK_GSCLNP_111, "aclk_gsclnp_111", "mout_aclk_gscl_111_user", + ENABLE_ACLK_GSCL, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_GSCLRTND_333, "aclk_gsclrtnd_333", + "mout_aclk_gscl_333_user", ENABLE_ACLK_GSCL, 5, 0, 0), + GATE(CLK_ACLK_GSCLBEND_333, "aclk_gsclbend_333", + "mout_aclk_gscl_333_user", ENABLE_ACLK_GSCL, 4, 0, 0), + GATE(CLK_ACLK_GSD, "aclk_gsd", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 3, 0, 0), + GATE(CLK_ACLK_GSCL2, "aclk_gscl2", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 2, 0, 0), + GATE(CLK_ACLK_GSCL1, "aclk_gscl1", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 1, 0, 0), + GATE(CLK_ACLK_GSCL0, "aclk_gscl0", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 0, 0, 0), + + /* ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0 */ + GATE(CLK_ACLK_SMMU_GSCL0, "aclk_smmu_gscl0", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + + /* ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1 */ + GATE(CLK_ACLK_SMMU_GSCL1, "aclk_smmu_gscl1", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1, 0, 0, 0), + + /* ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2 */ + GATE(CLK_ACLK_SMMU_GSCL2, "aclk_smmu_gscl2", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2, 0, 0, 0), + + /* ENABLE_PCLK_GSCL */ + GATE(CLK_PCLK_BTS_GSCL2, "pclk_bts_gscl2", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 7, 0, 0), + GATE(CLK_PCLK_BTS_GSCL1, "pclk_bts_gscl1", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 6, 0, 0), + GATE(CLK_PCLK_BTS_GSCL0, "pclk_bts_gscl0", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 5, 0, 0), + GATE(CLK_PCLK_PMU_GSCL, "pclk_pmu_gscl", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_GSCL, "pclk_sysreg_gscl", + "mout_aclk_gscl_111_user", ENABLE_PCLK_GSCL, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GSCL2, "pclk_gscl2", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 2, 0, 0), + GATE(CLK_PCLK_GSCL1, "pclk_gscl1", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 1, 0, 0), + GATE(CLK_PCLK_GSCL0, "pclk_gscl0", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 0, 0, 0), + + /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0 */ + GATE(CLK_PCLK_SMMU_GSCL0, "pclk_smmu_gscl0", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + + /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1 */ + GATE(CLK_PCLK_SMMU_GSCL1, "pclk_smmu_gscl1", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + + /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2 */ + GATE(CLK_PCLK_SMMU_GSCL2, "pclk_smmu_gscl2", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), +}; + +static struct samsung_cmu_info gscl_cmu_info __initdata = { + .mux_clks = gscl_mux_clks, + .nr_mux_clks = ARRAY_SIZE(gscl_mux_clks), + .gate_clks = gscl_gate_clks, + .nr_gate_clks = ARRAY_SIZE(gscl_gate_clks), + .nr_clk_ids = GSCL_NR_CLK, + .clk_regs = gscl_clk_regs, + .nr_clk_regs = ARRAY_SIZE(gscl_clk_regs), +}; + +static void __init exynos5433_cmu_gscl_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &gscl_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl", + exynos5433_cmu_gscl_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 60ccc169e9ff..fef8893c3ec2 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -147,8 +147,10 @@ #define CLK_SCLK_UFSUNIPRO_FSYS 229 #define CLK_SCLK_USBHOST30_FSYS 230 #define CLK_SCLK_USBDRD30_FSYS 231 +#define CLK_ACLK_GSCL_111 232 +#define CLK_ACLK_GSCL_333 233 -#define TOP_NR_CLK 232 +#define TOP_NR_CLK 234 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -819,4 +821,37 @@ #define G3D_NR_CLK 20 +/* CMU_GSCL */ +#define CLK_MOUT_ACLK_GSCL_111_USER 1 +#define CLK_MOUT_ACLK_GSCL_333_USER 2 + +#define CLK_ACLK_BTS_GSCL2 3 +#define CLK_ACLK_BTS_GSCL1 4 +#define CLK_ACLK_BTS_GSCL0 5 +#define CLK_ACLK_AHB2APB_GSCLP 6 +#define CLK_ACLK_XIU_GSCLX 7 +#define CLK_ACLK_GSCLNP_111 8 +#define CLK_ACLK_GSCLRTND_333 9 +#define CLK_ACLK_GSCLBEND_333 10 +#define CLK_ACLK_GSD 11 +#define CLK_ACLK_GSCL2 12 +#define CLK_ACLK_GSCL1 13 +#define CLK_ACLK_GSCL0 14 +#define CLK_ACLK_SMMU_GSCL0 15 +#define CLK_ACLK_SMMU_GSCL1 16 +#define CLK_ACLK_SMMU_GSCL2 17 +#define CLK_PCLK_BTS_GSCL2 18 +#define CLK_PCLK_BTS_GSCL1 19 +#define CLK_PCLK_BTS_GSCL0 20 +#define CLK_PCLK_PMU_GSCL 21 +#define CLK_PCLK_SYSREG_GSCL 22 +#define CLK_PCLK_GSCL2 23 +#define CLK_PCLK_GSCL1 24 +#define CLK_PCLK_GSCL0 25 +#define CLK_PCLK_SMMU_GSCL0 26 +#define CLK_PCLK_SMMU_GSCL1 27 +#define CLK_PCLK_SMMU_GSCL2 28 + +#define GSCL_NR_CLK 29 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From df40a13ca53e6f83ead88e718dd96654e75365ec Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:49 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_APOLLO domain This patch adds the mux/divider/gate clocks for CMU_APOLLO domain which generates the clocks for Cortex-A53 Quad-core processsor. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae [s.nawrocki@samsung.com: Renamed pclk_pmu_sysreg_apollo to pclk_sysreg_apollo] Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 15 ++ drivers/clk/samsung/clk-exynos5433.c | 193 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 37 ++++ 3 files changed, 245 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 9e7ed2d43a15..0a7146861a27 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -32,6 +32,8 @@ Required Properties: which generates clocks for 3D Graphics Engine IP. - "samsung,exynos5433-cmu-gscl" - clock controller compatible for CMU_GSCL which generates clocks for GSCALER IPs. + - "samsung,exynos5433-cmu-apollo"- clock controller compatible for CMU_APOLLO + which generates clocks for Cortex-A53 Quad-core processor. - reg: physical base address of the controller and length of memory mapped region. @@ -105,6 +107,10 @@ Required Properties: - aclk_gscl_111 - aclk_gscl_333 + Input clocks for apollo clock controller: + - oscclk + - sclk_bus_pll_apollo + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -289,6 +295,15 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_GSCL_333>; }; + cmu_apollo: clock-controller@11900000 { + compatible = "samsung,exynos5433-cmu-apollo"; + reg = <0x11900000 0x1088>; + #clock-cells = <1>; + + clock-names = "oscclk", "sclk_bus_pll_apollo"; + clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_APOLLO>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 12f60c6a5a7a..f7d1e8390cdf 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3393,3 +3393,196 @@ static void __init exynos5433_cmu_gscl_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl", exynos5433_cmu_gscl_init); + +/* + * Register offset definitions for CMU_APOLLO + */ +#define APOLLO_PLL_LOCK 0x0000 +#define APOLLO_PLL_CON0 0x0100 +#define APOLLO_PLL_CON1 0x0104 +#define APOLLO_PLL_FREQ_DET 0x010c +#define MUX_SEL_APOLLO0 0x0200 +#define MUX_SEL_APOLLO1 0x0204 +#define MUX_SEL_APOLLO2 0x0208 +#define MUX_ENABLE_APOLLO0 0x0300 +#define MUX_ENABLE_APOLLO1 0x0304 +#define MUX_ENABLE_APOLLO2 0x0308 +#define MUX_STAT_APOLLO0 0x0400 +#define MUX_STAT_APOLLO1 0x0404 +#define MUX_STAT_APOLLO2 0x0408 +#define DIV_APOLLO0 0x0600 +#define DIV_APOLLO1 0x0604 +#define DIV_APOLLO_PLL_FREQ_DET 0x0608 +#define DIV_STAT_APOLLO0 0x0700 +#define DIV_STAT_APOLLO1 0x0704 +#define DIV_STAT_APOLLO_PLL_FREQ_DET 0x0708 +#define ENABLE_ACLK_APOLLO 0x0800 +#define ENABLE_PCLK_APOLLO 0x0900 +#define ENABLE_SCLK_APOLLO 0x0a00 +#define ENABLE_IP_APOLLO0 0x0b00 +#define ENABLE_IP_APOLLO1 0x0b04 +#define CLKOUT_CMU_APOLLO 0x0c00 +#define CLKOUT_CMU_APOLLO_DIV_STAT 0x0c04 +#define ARMCLK_STOPCTRL 0x1000 +#define APOLLO_PWR_CTRL 0x1020 +#define APOLLO_PWR_CTRL2 0x1024 +#define APOLLO_INTR_SPREAD_ENABLE 0x1080 +#define APOLLO_INTR_SPREAD_USE_STANDBYWFI 0x1084 +#define APOLLO_INTR_SPREAD_BLOCKING_DURATION 0x1088 + +static unsigned long apollo_clk_regs[] __initdata = { + APOLLO_PLL_LOCK, + APOLLO_PLL_CON0, + APOLLO_PLL_CON1, + APOLLO_PLL_FREQ_DET, + MUX_SEL_APOLLO0, + MUX_SEL_APOLLO1, + MUX_SEL_APOLLO2, + MUX_ENABLE_APOLLO0, + MUX_ENABLE_APOLLO1, + MUX_ENABLE_APOLLO2, + MUX_STAT_APOLLO0, + MUX_STAT_APOLLO1, + MUX_STAT_APOLLO2, + DIV_APOLLO0, + DIV_APOLLO1, + DIV_APOLLO_PLL_FREQ_DET, + DIV_STAT_APOLLO0, + DIV_STAT_APOLLO1, + DIV_STAT_APOLLO_PLL_FREQ_DET, + ENABLE_ACLK_APOLLO, + ENABLE_PCLK_APOLLO, + ENABLE_SCLK_APOLLO, + ENABLE_IP_APOLLO0, + ENABLE_IP_APOLLO1, + CLKOUT_CMU_APOLLO, + CLKOUT_CMU_APOLLO_DIV_STAT, + ARMCLK_STOPCTRL, + APOLLO_PWR_CTRL, + APOLLO_PWR_CTRL2, + APOLLO_INTR_SPREAD_ENABLE, + APOLLO_INTR_SPREAD_USE_STANDBYWFI, + APOLLO_INTR_SPREAD_BLOCKING_DURATION, +}; + +/* list of all parent clock list */ +PNAME(mout_apollo_pll_p) = { "oscclk", "fout_apollo_pll", }; +PNAME(mout_bus_pll_apollo_user_p) = { "oscclk", "sclk_bus_pll_apollo", }; +PNAME(mout_apollo_p) = { "mout_apollo_pll", + "mout_bus_pll_apollo_user", }; + +static struct samsung_pll_clock apollo_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_APOLLO_PLL, "fout_apollo_pll", "oscclk", + APOLLO_PLL_LOCK, APOLLO_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_mux_clock apollo_mux_clks[] __initdata = { + /* MUX_SEL_APOLLO0 */ + MUX_F(CLK_MOUT_APOLLO_PLL, "mout_apollo_pll", mout_apollo_pll_p, + MUX_SEL_APOLLO0, 0, 1, 0, CLK_MUX_READ_ONLY), + + /* MUX_SEL_APOLLO1 */ + MUX(CLK_MOUT_BUS_PLL_APOLLO_USER, "mout_bus_pll_apollo_user", + mout_bus_pll_apollo_user_p, MUX_SEL_APOLLO1, 0, 1), + + /* MUX_SEL_APOLLO2 */ + MUX_F(CLK_MOUT_APOLLO, "mout_apollo", mout_apollo_p, MUX_SEL_APOLLO2, + 0, 1, 0, CLK_MUX_READ_ONLY), +}; + +static struct samsung_div_clock apollo_div_clks[] __initdata = { + /* DIV_APOLLO0 */ + DIV_F(CLK_DIV_CNTCLK_APOLLO, "div_cntclk_apollo", "div_apollo2", + DIV_APOLLO0, 24, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_DBG_APOLLO, "div_pclk_dbg_apollo", "div_apollo2", + DIV_APOLLO0, 20, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATCLK_APOLLO, "div_atclk_apollo", "div_apollo2", + DIV_APOLLO0, 16, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_APOLLO, "div_pclk_apollo", "div_apollo2", + DIV_APOLLO0, 12, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ACLK_APOLLO, "div_aclk_apollo", "div_apollo2", + DIV_APOLLO0, 8, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_APOLLO2, "div_apollo2", "div_apollo1", + DIV_APOLLO0, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_APOLLO1, "div_apollo1", "mout_apollo", + DIV_APOLLO0, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + + /* DIV_APOLLO1 */ + DIV_F(CLK_DIV_SCLK_HPM_APOLLO, "div_sclk_hpm_apollo", "mout_apollo", + DIV_APOLLO1, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_APOLLO_PLL, "div_apollo_pll", "mout_apollo", + DIV_APOLLO1, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), +}; + +static struct samsung_gate_clock apollo_gate_clks[] __initdata = { + /* ENABLE_ACLK_APOLLO */ + GATE(CLK_ACLK_ASATBSLV_APOLLO_3_CSSYS, "aclk_asatbslv_apollo_3_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASATBSLV_APOLLO_2_CSSYS, "aclk_asatbslv_apollo_2_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASATBSLV_APOLLO_1_CSSYS, "aclk_asatbslv_apollo_1_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASATBSLV_APOLLO_0_CSSYS, "aclk_asatbslv_apollo_0_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCACES_APOLLO_CCI, "aclk_asyncaces_apollo_cci", + "div_aclk_apollo", ENABLE_ACLK_APOLLO, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_APOLLOP, "aclk_ahb2apb_apollop", + "div_pclk_apollo", ENABLE_ACLK_APOLLO, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_APOLLONP_200, "aclk_apollonp_200", + "div_pclk_apollo", ENABLE_ACLK_APOLLO, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_APOLLO */ + GATE(CLK_PCLK_ASAPBMST_CSSYS_APOLLO, "pclk_asapbmst_cssys_apollo", + "div_pclk_dbg_apollo", ENABLE_PCLK_APOLLO, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_APOLLO, "pclk_pmu_apollo", "div_pclk_apollo", + ENABLE_PCLK_APOLLO, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_APOLLO, "pclk_sysreg_apollo", + "div_pclk_apollo", ENABLE_PCLK_APOLLO, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_APOLLO */ + GATE(CLK_CNTCLK_APOLLO, "cntclk_apollo", "div_cntclk_apollo", + ENABLE_SCLK_APOLLO, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_HPM_APOLLO, "sclk_hpm_apollo", "div_sclk_hpm_apollo", + ENABLE_SCLK_APOLLO, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_APOLLO, "sclk_apollo", "div_apollo_pll", + ENABLE_SCLK_APOLLO, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info apollo_cmu_info __initdata = { + .pll_clks = apollo_pll_clks, + .nr_pll_clks = ARRAY_SIZE(apollo_pll_clks), + .mux_clks = apollo_mux_clks, + .nr_mux_clks = ARRAY_SIZE(apollo_mux_clks), + .div_clks = apollo_div_clks, + .nr_div_clks = ARRAY_SIZE(apollo_div_clks), + .gate_clks = apollo_gate_clks, + .nr_gate_clks = ARRAY_SIZE(apollo_gate_clks), + .nr_clk_ids = APOLLO_NR_CLK, + .clk_regs = apollo_clk_regs, + .nr_clk_regs = ARRAY_SIZE(apollo_clk_regs), +}; + +static void __init exynos5433_cmu_apollo_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &apollo_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_apollo, "samsung,exynos5433-cmu-apollo", + exynos5433_cmu_apollo_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index fef8893c3ec2..90184e3a42d5 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -854,4 +854,41 @@ #define GSCL_NR_CLK 29 +/* CMU_APOLLO */ +#define CLK_FOUT_APOLLO_PLL 1 + +#define CLK_MOUT_APOLLO_PLL 2 +#define CLK_MOUT_BUS_PLL_APOLLO_USER 3 +#define CLK_MOUT_APOLLO 4 + +#define CLK_DIV_CNTCLK_APOLLO 5 +#define CLK_DIV_PCLK_DBG_APOLLO 6 +#define CLK_DIV_ATCLK_APOLLO 7 +#define CLK_DIV_PCLK_APOLLO 8 +#define CLK_DIV_ACLK_APOLLO 9 +#define CLK_DIV_APOLLO2 10 +#define CLK_DIV_APOLLO1 11 +#define CLK_DIV_SCLK_HPM_APOLLO 12 +#define CLK_DIV_APOLLO_PLL 13 + +#define CLK_ACLK_ATBDS_APOLLO_3 14 +#define CLK_ACLK_ATBDS_APOLLO_2 15 +#define CLK_ACLK_ATBDS_APOLLO_1 16 +#define CLK_ACLK_ATBDS_APOLLO_0 17 +#define CLK_ACLK_ASATBSLV_APOLLO_3_CSSYS 18 +#define CLK_ACLK_ASATBSLV_APOLLO_2_CSSYS 19 +#define CLK_ACLK_ASATBSLV_APOLLO_1_CSSYS 20 +#define CLK_ACLK_ASATBSLV_APOLLO_0_CSSYS 21 +#define CLK_ACLK_ASYNCACES_APOLLO_CCI 22 +#define CLK_ACLK_AHB2APB_APOLLOP 23 +#define CLK_ACLK_APOLLONP_200 24 +#define CLK_PCLK_ASAPBMST_CSSYS_APOLLO 25 +#define CLK_PCLK_PMU_APOLLO 26 +#define CLK_PCLK_SYSREG_APOLLO 27 +#define CLK_CNTCLK_APOLLO 28 +#define CLK_SCLK_HPM_APOLLO 29 +#define CLK_SCLK_APOLLO 30 + +#define APOLLO_NR_CLK 31 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 6c5d76d15ab6da9b30af020a44e071eb5145e1a0 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:50 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_ATLAS domain This patch adds the mux/divider/gate clocks for CMU_ATLAS domain which generates the clocks for Cortex-A57 Quad-core processsor, L2 cache controller and CoreSight. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 16 ++ drivers/clk/samsung/clk-exynos5433.c | 219 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 46 +++++ 3 files changed, 281 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 0a7146861a27..7c1dccc4d72e 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -34,6 +34,9 @@ Required Properties: which generates clocks for GSCALER IPs. - "samsung,exynos5433-cmu-apollo"- clock controller compatible for CMU_APOLLO which generates clocks for Cortex-A53 Quad-core processor. + - "samsung,exynos5433-cmu-atlas" - clock controller compatible for CMU_ATLAS + which generates clocks for Cortex-A57 Quad-core processor, CoreSight and + L2 cache controller. - reg: physical base address of the controller and length of memory mapped region. @@ -111,6 +114,10 @@ Required Properties: - oscclk - sclk_bus_pll_apollo + Input clocks for atlas clock controller: + - oscclk + - sclk_bus_pll_atlas + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -304,6 +311,15 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_APOLLO>; }; + cmu_atlas: clock-controller@11800000 { + compatible = "samsung,exynos5433-cmu-atlas"; + reg = <0x11800000 0x1088>; + #clock-cells = <1>; + + clock-names = "oscclk", "sclk_bus_pll_atlas"; + clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_ATLAS>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index f7d1e8390cdf..c44062d2904e 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3586,3 +3586,222 @@ static void __init exynos5433_cmu_apollo_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_apollo, "samsung,exynos5433-cmu-apollo", exynos5433_cmu_apollo_init); + +/* + * Register offset definitions for CMU_ATLAS + */ +#define ATLAS_PLL_LOCK 0x0000 +#define ATLAS_PLL_CON0 0x0100 +#define ATLAS_PLL_CON1 0x0104 +#define ATLAS_PLL_FREQ_DET 0x010c +#define MUX_SEL_ATLAS0 0x0200 +#define MUX_SEL_ATLAS1 0x0204 +#define MUX_SEL_ATLAS2 0x0208 +#define MUX_ENABLE_ATLAS0 0x0300 +#define MUX_ENABLE_ATLAS1 0x0304 +#define MUX_ENABLE_ATLAS2 0x0308 +#define MUX_STAT_ATLAS0 0x0400 +#define MUX_STAT_ATLAS1 0x0404 +#define MUX_STAT_ATLAS2 0x0408 +#define DIV_ATLAS0 0x0600 +#define DIV_ATLAS1 0x0604 +#define DIV_ATLAS_PLL_FREQ_DET 0x0608 +#define DIV_STAT_ATLAS0 0x0700 +#define DIV_STAT_ATLAS1 0x0704 +#define DIV_STAT_ATLAS_PLL_FREQ_DET 0x0708 +#define ENABLE_ACLK_ATLAS 0x0800 +#define ENABLE_PCLK_ATLAS 0x0900 +#define ENABLE_SCLK_ATLAS 0x0a00 +#define ENABLE_IP_ATLAS0 0x0b00 +#define ENABLE_IP_ATLAS1 0x0b04 +#define CLKOUT_CMU_ATLAS 0x0c00 +#define CLKOUT_CMU_ATLAS_DIV_STAT 0x0c04 +#define ARMCLK_STOPCTRL 0x1000 +#define ATLAS_PWR_CTRL 0x1020 +#define ATLAS_PWR_CTRL2 0x1024 +#define ATLAS_INTR_SPREAD_ENABLE 0x1080 +#define ATLAS_INTR_SPREAD_USE_STANDBYWFI 0x1084 +#define ATLAS_INTR_SPREAD_BLOCKING_DURATION 0x1088 + +static unsigned long atlas_clk_regs[] __initdata = { + ATLAS_PLL_LOCK, + ATLAS_PLL_CON0, + ATLAS_PLL_CON1, + ATLAS_PLL_FREQ_DET, + MUX_SEL_ATLAS0, + MUX_SEL_ATLAS1, + MUX_SEL_ATLAS2, + MUX_ENABLE_ATLAS0, + MUX_ENABLE_ATLAS1, + MUX_ENABLE_ATLAS2, + MUX_STAT_ATLAS0, + MUX_STAT_ATLAS1, + MUX_STAT_ATLAS2, + DIV_ATLAS0, + DIV_ATLAS1, + DIV_ATLAS_PLL_FREQ_DET, + DIV_STAT_ATLAS0, + DIV_STAT_ATLAS1, + DIV_STAT_ATLAS_PLL_FREQ_DET, + ENABLE_ACLK_ATLAS, + ENABLE_PCLK_ATLAS, + ENABLE_SCLK_ATLAS, + ENABLE_IP_ATLAS0, + ENABLE_IP_ATLAS1, + CLKOUT_CMU_ATLAS, + CLKOUT_CMU_ATLAS_DIV_STAT, + ARMCLK_STOPCTRL, + ATLAS_PWR_CTRL, + ATLAS_PWR_CTRL2, + ATLAS_INTR_SPREAD_ENABLE, + ATLAS_INTR_SPREAD_USE_STANDBYWFI, + ATLAS_INTR_SPREAD_BLOCKING_DURATION, +}; + +/* list of all parent clock list */ +PNAME(mout_atlas_pll_p) = { "oscclk", "fout_atlas_pll", }; +PNAME(mout_bus_pll_atlas_user_p) = { "oscclk", "sclk_bus_pll_atlas", }; +PNAME(mout_atlas_p) = { "mout_atlas_pll", + "mout_bus_pll_atlas_user", }; + +static struct samsung_pll_clock atlas_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_ATLAS_PLL, "fout_atlas_pll", "oscclk", + ATLAS_PLL_LOCK, ATLAS_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_mux_clock atlas_mux_clks[] __initdata = { + /* MUX_SEL_ATLAS0 */ + MUX_F(CLK_MOUT_ATLAS_PLL, "mout_atlas_pll", mout_atlas_pll_p, + MUX_SEL_ATLAS0, 0, 1, 0, CLK_MUX_READ_ONLY), + + /* MUX_SEL_ATLAS1 */ + MUX(CLK_MOUT_BUS_PLL_ATLAS_USER, "mout_bus_pll_atlas_user", + mout_bus_pll_atlas_user_p, MUX_SEL_ATLAS1, 0, 1), + + /* MUX_SEL_ATLAS2 */ + MUX_F(CLK_MOUT_ATLAS, "mout_atlas", mout_atlas_p, MUX_SEL_ATLAS2, + 0, 1, 0, CLK_MUX_READ_ONLY), +}; + +static struct samsung_div_clock atlas_div_clks[] __initdata = { + /* DIV_ATLAS0 */ + DIV_F(CLK_DIV_CNTCLK_ATLAS, "div_cntclk_atlas", "div_atlas2", + DIV_ATLAS0, 24, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_DBG_ATLAS, "div_pclk_dbg_atlas", "div_atclk_atlas", + DIV_ATLAS0, 20, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATCLK_ATLASO, "div_atclk_atlas", "div_atlas2", + DIV_ATLAS0, 16, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_ATLAS, "div_pclk_atlas", "div_atlas2", + DIV_ATLAS0, 12, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ACLK_ATLAS, "div_aclk_atlas", "div_atlas2", + DIV_ATLAS0, 8, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATLAS2, "div_atlas2", "div_atlas1", + DIV_ATLAS0, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATLAS1, "div_atlas1", "mout_atlas", + DIV_ATLAS0, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + + /* DIV_ATLAS1 */ + DIV_F(CLK_DIV_SCLK_HPM_ATLAS, "div_sclk_hpm_atlas", "mout_atlas", + DIV_ATLAS1, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATLAS_PLL, "div_atlas_pll", "mout_atlas", + DIV_ATLAS1, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), +}; + +static struct samsung_gate_clock atlas_gate_clks[] __initdata = { + /* ENABLE_ACLK_ATLAS */ + GATE(CLK_ACLK_ATB_AUD_CSSYS, "aclk_atb_aud_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO3_CSSYS, "aclk_atb_apollo3_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO2_CSSYS, "aclk_atb_apollo2_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO1_CSSYS, "aclk_atb_apollo1_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO0_CSSYS, "aclk_atb_apollo0_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBS_CSSYS_SSS, "aclk_asyncahbs_cssys_sss", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CSSYS_CCIX, "aclk_asyncaxis_cssys_ccix", + "div_pclk_dbg_atlas", ENABLE_ACLK_ATLAS, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCACES_ATLAS_CCI, "aclk_asyncaces_atlas_cci", + "div_aclk_atlas", ENABLE_ACLK_ATLAS, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ATLASP, "aclk_ahb2apb_atlasp", "div_pclk_atlas", + ENABLE_ACLK_ATLAS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATLASNP_200, "aclk_atlasnp_200", "div_pclk_atlas", + ENABLE_ACLK_ATLAS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_ATLAS */ + GATE(CLK_PCLK_ASYNCAPB_AUD_CSSYS, "pclk_asyncapb_aud_cssys", + "div_pclk_dbg_atlas", ENABLE_PCLK_ATLAS, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAPB_ISP_CSSYS, "pclk_asyncapb_isp_cssys", + "div_pclk_dbg_atlas", ENABLE_PCLK_ATLAS, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAPB_APOLLO_CSSYS, "pclk_asyncapb_apollo_cssys", + "div_pclk_dbg_atlas", ENABLE_PCLK_ATLAS, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_ATLAS, "pclk_pmu_atlas", "div_pclk_atlas", + ENABLE_PCLK_ATLAS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_ATLAS, "pclk_sysreg_atlas", "div_pclk_atlas", + ENABLE_PCLK_ATLAS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SECJTAG, "pclk_secjtag", "div_pclk_dbg_atlas", + ENABLE_PCLK_ATLAS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_ATLAS */ + GATE(CLK_CNTCLK_ATLAS, "cntclk_atlas", "div_cntclk_atlas", + ENABLE_SCLK_ATLAS, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_HPM_ATLAS, "sclk_hpm_atlas", "div_sclk_hpm_atlas", + ENABLE_SCLK_ATLAS, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_TRACECLK, "traceclk", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CTMCLK, "ctmclk", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_HCLK_CSSYS, "hclk_cssys", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DBG_CSSYS, "pclk_dbg_cssys", "div_pclk_dbg_atlas", + ENABLE_SCLK_ATLAS, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DBG, "pclk_dbg", "div_pclk_dbg_atlas", + ENABLE_SCLK_ATLAS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ATCLK, "atclk", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_ATLAS, "sclk_atlas", "div_atlas2", + ENABLE_SCLK_ATLAS, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info atlas_cmu_info __initdata = { + .pll_clks = atlas_pll_clks, + .nr_pll_clks = ARRAY_SIZE(atlas_pll_clks), + .mux_clks = atlas_mux_clks, + .nr_mux_clks = ARRAY_SIZE(atlas_mux_clks), + .div_clks = atlas_div_clks, + .nr_div_clks = ARRAY_SIZE(atlas_div_clks), + .gate_clks = atlas_gate_clks, + .nr_gate_clks = ARRAY_SIZE(atlas_gate_clks), + .nr_clk_ids = ATLAS_NR_CLK, + .clk_regs = atlas_clk_regs, + .nr_clk_regs = ARRAY_SIZE(atlas_clk_regs), +}; + +static void __init exynos5433_cmu_atlas_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &atlas_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_atlas, "samsung,exynos5433-cmu-atlas", + exynos5433_cmu_atlas_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 90184e3a42d5..cdc91f7e6ec8 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -891,4 +891,50 @@ #define APOLLO_NR_CLK 31 +/* CMU_ATLAS */ +#define CLK_FOUT_ATLAS_PLL 1 + +#define CLK_MOUT_ATLAS_PLL 2 +#define CLK_MOUT_BUS_PLL_ATLAS_USER 3 +#define CLK_MOUT_ATLAS 4 + +#define CLK_DIV_CNTCLK_ATLAS 5 +#define CLK_DIV_PCLK_DBG_ATLAS 6 +#define CLK_DIV_ATCLK_ATLASO 7 +#define CLK_DIV_PCLK_ATLAS 8 +#define CLK_DIV_ACLK_ATLAS 9 +#define CLK_DIV_ATLAS2 10 +#define CLK_DIV_ATLAS1 11 +#define CLK_DIV_SCLK_HPM_ATLAS 12 +#define CLK_DIV_ATLAS_PLL 13 + +#define CLK_ACLK_ATB_AUD_CSSYS 14 +#define CLK_ACLK_ATB_APOLLO3_CSSYS 15 +#define CLK_ACLK_ATB_APOLLO2_CSSYS 16 +#define CLK_ACLK_ATB_APOLLO1_CSSYS 17 +#define CLK_ACLK_ATB_APOLLO0_CSSYS 18 +#define CLK_ACLK_ASYNCAHBS_CSSYS_SSS 19 +#define CLK_ACLK_ASYNCAXIS_CSSYS_CCIX 20 +#define CLK_ACLK_ASYNCACES_ATLAS_CCI 21 +#define CLK_ACLK_AHB2APB_ATLASP 22 +#define CLK_ACLK_ATLASNP_200 23 +#define CLK_PCLK_ASYNCAPB_AUD_CSSYS 24 +#define CLK_PCLK_ASYNCAPB_ISP_CSSYS 25 +#define CLK_PCLK_ASYNCAPB_APOLLO_CSSYS 26 +#define CLK_PCLK_PMU_ATLAS 27 +#define CLK_PCLK_SYSREG_ATLAS 28 +#define CLK_PCLK_SECJTAG 29 +#define CLK_CNTCLK_ATLAS 30 +#define CLK_SCLK_FREQ_DET_ATLAS_PLL 31 +#define CLK_SCLK_HPM_ATLAS 32 +#define CLK_TRACECLK 33 +#define CLK_CTMCLK 34 +#define CLK_HCLK_CSSYS 35 +#define CLK_PCLK_DBG_CSSYS 36 +#define CLK_PCLK_DBG 37 +#define CLK_ATCLK 38 +#define CLK_SCLK_ATLAS 39 + +#define ATLAS_NR_CLK 40 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From b274bbfd8b4a94cb5bd6fe21801264a27dd8ec75 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:51 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_MSCL domain This patch adds the mux/divider/gate clocks for CMU_MSCL domain which generates the clocks for M2M (Memory to Memory) scaler, JPEG IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 20 +++ drivers/clk/samsung/clk-exynos5433.c | 185 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 41 ++++- 3 files changed, 245 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 7c1dccc4d72e..ecb9534c2ea6 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -37,6 +37,8 @@ Required Properties: - "samsung,exynos5433-cmu-atlas" - clock controller compatible for CMU_ATLAS which generates clocks for Cortex-A57 Quad-core processor, CoreSight and L2 cache controller. + - "samsung,exynos5433-cmu-mscl" - clock controller compatible for CMU_MSCL + which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -118,6 +120,11 @@ Required Properties: - oscclk - sclk_bus_pll_atlas + Input clocks for mscl clock controller: + - oscclk + - sclk_jpeg_mscl + - aclk_mscl_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -320,6 +327,19 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_ATLAS>; }; + cmu_mscl: clock-controller@105d0000 { + compatible = "samsung,exynos5433-cmu-mscl"; + reg = <0x105d0000 0x0b10>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_jpeg_mscl", + "aclk_mscl_400"; + clocks = <&xxti>, + <&cmu_top CLK_SCLK_JPEG_MSCL>, + <&cmu_top CLK_ACLK_MSCL_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index c44062d2904e..d272e42eb48c 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -419,6 +419,8 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV_TOP1, 0, 3), /* DIV_TOP2 */ + DIV(CLK_DIV_ACLK_MSCL_400, "div_aclk_mscl_400", "mout_aclk_mscl_400_b", + DIV_TOP2, 4, 3), DIV(CLK_DIV_ACLK_FSYS_200, "div_aclk_fsys_200", "mout_bus_pll_user", DIV_TOP2, 0, 3), @@ -446,6 +448,10 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_ACLK_BUS1_400, "div_aclk_bus1_400", "mout_bus_pll_user", DIV_TOP4, 0, 3), + /* DIV_TOP_MSCL */ + DIV(CLK_DIV_SCLK_JPEG, "div_sclk_jpeg", "mout_sclk_jpeg_c", + DIV_TOP_MSCL, 0, 4), + /* DIV_TOP_FSYS0 */ DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", DIV_TOP_FSYS0, 16, 8), @@ -542,6 +548,9 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_PERIS_66, "aclk_peris_66", "div_aclk_peris_66_b", ENABLE_ACLK_TOP, 21, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MSCL_400, "aclk_mscl_400", "div_aclk_mscl_400", + ENABLE_ACLK_TOP, 19, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_FSYS_200, "aclk_fsys_200", "div_aclk_fsys_200", ENABLE_ACLK_TOP, 18, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -558,6 +567,10 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { ENABLE_ACLK_TOP, 0, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + /* ENABLE_SCLK_TOP_MSCL */ + GATE(CLK_SCLK_JPEG_MSCL, "sclk_jpeg_mscl", "div_sclk_jpeg", + ENABLE_SCLK_TOP_MSCL, 0, 0, 0), + /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", ENABLE_SCLK_TOP_FSYS, 7, 0, 0), @@ -3805,3 +3818,175 @@ static void __init exynos5433_cmu_atlas_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_atlas, "samsung,exynos5433-cmu-atlas", exynos5433_cmu_atlas_init); + +/* + * Register offset definitions for CMU_MSCL + */ +#define MUX_SEL_MSCL0 0x0200 +#define MUX_SEL_MSCL1 0x0204 +#define MUX_ENABLE_MSCL0 0x0300 +#define MUX_ENABLE_MSCL1 0x0304 +#define MUX_STAT_MSCL0 0x0400 +#define MUX_STAT_MSCL1 0x0404 +#define DIV_MSCL 0x0600 +#define DIV_STAT_MSCL 0x0700 +#define ENABLE_ACLK_MSCL 0x0800 +#define ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0 0x0804 +#define ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1 0x0808 +#define ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG 0x080c +#define ENABLE_PCLK_MSCL 0x0900 +#define ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0 0x0904 +#define ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1 0x0908 +#define ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG 0x000c +#define ENABLE_SCLK_MSCL 0x0a00 +#define ENABLE_IP_MSCL0 0x0b00 +#define ENABLE_IP_MSCL1 0x0b04 +#define ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER0 0x0b08 +#define ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER1 0x0b0c +#define ENABLE_IP_MSCL_SECURE_SMMU_JPEG 0x0b10 + +static unsigned long mscl_clk_regs[] __initdata = { + MUX_SEL_MSCL0, + MUX_SEL_MSCL1, + MUX_ENABLE_MSCL0, + MUX_ENABLE_MSCL1, + MUX_STAT_MSCL0, + MUX_STAT_MSCL1, + DIV_MSCL, + DIV_STAT_MSCL, + ENABLE_ACLK_MSCL, + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0, + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1, + ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG, + ENABLE_PCLK_MSCL, + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0, + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1, + ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG, + ENABLE_SCLK_MSCL, + ENABLE_IP_MSCL0, + ENABLE_IP_MSCL1, + ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER0, + ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER1, + ENABLE_IP_MSCL_SECURE_SMMU_JPEG, +}; + +/* list of all parent clock list */ +PNAME(mout_sclk_jpeg_user_p) = { "oscclk", "sclk_jpeg_mscl", }; +PNAME(mout_aclk_mscl_400_user_p) = { "oscclk", "aclk_mscl_400", }; +PNAME(mout_sclk_jpeg_p) = { "mout_sclk_jpeg_user", + "mout_aclk_mscl_400_user", }; + +static struct samsung_mux_clock mscl_mux_clks[] __initdata = { + /* MUX_SEL_MSCL0 */ + MUX(CLK_MOUT_SCLK_JPEG_USER, "mout_sclk_jpeg_user", + mout_sclk_jpeg_user_p, MUX_SEL_MSCL0, 4, 1), + MUX(CLK_MOUT_ACLK_MSCL_400_USER, "mout_aclk_mscl_400_user", + mout_aclk_mscl_400_user_p, MUX_SEL_MSCL0, 0, 1), + + /* MUX_SEL_MSCL1 */ + MUX(CLK_MOUT_SCLK_JPEG, "mout_sclk_jpeg", mout_sclk_jpeg_p, + MUX_SEL_MSCL1, 0, 1), +}; + +static struct samsung_div_clock mscl_div_clks[] __initdata = { + /* DIV_MSCL */ + DIV(CLK_DIV_PCLK_MSCL, "div_pclk_mscl", "mout_aclk_mscl_400_user", + DIV_MSCL, 0, 3), +}; + +static struct samsung_gate_clock mscl_gate_clks[] __initdata = { + /* ENABLE_ACLK_MSCL */ + GATE(CLK_ACLK_BTS_JPEG, "aclk_bts_jpeg", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 9, 0, 0), + GATE(CLK_ACLK_BTS_M2MSCALER1, "aclk_bts_m2mscaler1", + "mout_aclk_mscl_400_user", ENABLE_ACLK_MSCL, 8, 0, 0), + GATE(CLK_ACLK_BTS_M2MSCALER0, "aclk_bts_m2mscaler0", + "mout_aclk_mscl_400_user", ENABLE_ACLK_MSCL, 7, 0, 0), + GATE(CLK_ACLK_AHB2APB_MSCL0P, "aclk_abh2apb_mscl0p", "div_pclk_mscl", + ENABLE_ACLK_MSCL, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_MSCLX, "aclk_xiu_msclx", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MSCLNP_100, "aclk_msclnp_100", "div_pclk_mscl", + ENABLE_ACLK_MSCL, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MSCLND_400, "aclk_msclnd_400", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_JPEG, "aclk_jpeg", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 2, 0, 0), + GATE(CLK_ACLK_M2MSCALER1, "aclk_m2mscaler1", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 1, 0, 0), + GATE(CLK_ACLK_M2MSCALER0, "aclk_m2mscaler0", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 0, 0, 0), + + /* ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0 */ + GATE(CLK_ACLK_SMMU_M2MSCALER0, "aclk_smmu_m2mscaler0", + "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1 */ + GATE(CLK_ACLK_SMMU_M2MSCALER1, "aclk_smmu_m2mscaler1", + "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG */ + GATE(CLK_ACLK_SMMU_JPEG, "aclk_smmu_jpeg", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MSCL */ + GATE(CLK_PCLK_BTS_JPEG, "pclk_bts_jpeg", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 7, 0, 0), + GATE(CLK_PCLK_BTS_M2MSCALER1, "pclk_bts_m2mscaler1", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 6, 0, 0), + GATE(CLK_PCLK_BTS_M2MSCALER0, "pclk_bts_m2mscaler0", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 5, 0, 0), + GATE(CLK_PCLK_PMU_MSCL, "pclk_pmu_mscl", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_MSCL, "pclk_sysreg_mscl", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_JPEG, "pclk_jpeg", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 2, 0, 0), + GATE(CLK_PCLK_M2MSCALER1, "pclk_m2mscaler1", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 1, 0, 0), + GATE(CLK_PCLK_M2MSCALER0, "pclk_m2mscaler0", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 0, 0, 0), + + /* ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0 */ + GATE(CLK_PCLK_SMMU_M2MSCALER0, "pclk_smmu_m2mscaler0", "div_pclk_mscl", + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1 */ + GATE(CLK_PCLK_SMMU_M2MSCALER1, "pclk_smmu_m2mscaler1", "div_pclk_mscl", + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG */ + GATE(CLK_PCLK_SMMU_JPEG, "pclk_smmu_jpeg", "div_pclk_mscl", + ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_MSCL */ + GATE(CLK_SCLK_JPEG, "sclk_jpeg", "mout_sclk_jpeg", ENABLE_SCLK_MSCL, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), +}; + +static struct samsung_cmu_info mscl_cmu_info __initdata = { + .mux_clks = mscl_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mscl_mux_clks), + .div_clks = mscl_div_clks, + .nr_div_clks = ARRAY_SIZE(mscl_div_clks), + .gate_clks = mscl_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mscl_gate_clks), + .nr_clk_ids = MSCL_NR_CLK, + .clk_regs = mscl_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mscl_clk_regs), +}; + +static void __init exynos5433_cmu_mscl_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &mscl_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl", + exynos5433_cmu_mscl_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index cdc91f7e6ec8..9898390710e6 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -114,6 +114,8 @@ #define CLK_DIV_SCLK_USBHOST30 141 #define CLK_DIV_SCLK_UFSUNIPRO 142 #define CLK_DIV_SCLK_USBDRD30 143 +#define CLK_DIV_SCLK_JPEG 144 +#define CLK_DIV_ACLK_MSCL_400 145 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -149,8 +151,10 @@ #define CLK_SCLK_USBDRD30_FSYS 231 #define CLK_ACLK_GSCL_111 232 #define CLK_ACLK_GSCL_333 233 +#define CLK_SCLK_JPEG_MSCL 234 +#define CLK_ACLK_MSCL_400 235 -#define TOP_NR_CLK 234 +#define TOP_NR_CLK 236 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -937,4 +941,39 @@ #define ATLAS_NR_CLK 40 +/* CMU_MSCL */ +#define CLK_MOUT_SCLK_JPEG_USER 1 +#define CLK_MOUT_ACLK_MSCL_400_USER 2 +#define CLK_MOUT_SCLK_JPEG 3 + +#define CLK_DIV_PCLK_MSCL 4 + +#define CLK_ACLK_BTS_JPEG 5 +#define CLK_ACLK_BTS_M2MSCALER1 6 +#define CLK_ACLK_BTS_M2MSCALER0 7 +#define CLK_ACLK_AHB2APB_MSCL0P 8 +#define CLK_ACLK_XIU_MSCLX 9 +#define CLK_ACLK_MSCLNP_100 10 +#define CLK_ACLK_MSCLND_400 11 +#define CLK_ACLK_JPEG 12 +#define CLK_ACLK_M2MSCALER1 13 +#define CLK_ACLK_M2MSCALER0 14 +#define CLK_ACLK_SMMU_M2MSCALER0 15 +#define CLK_ACLK_SMMU_M2MSCALER1 16 +#define CLK_ACLK_SMMU_JPEG 17 +#define CLK_PCLK_BTS_JPEG 18 +#define CLK_PCLK_BTS_M2MSCALER1 19 +#define CLK_PCLK_BTS_M2MSCALER0 20 +#define CLK_PCLK_PMU_MSCL 21 +#define CLK_PCLK_SYSREG_MSCL 22 +#define CLK_PCLK_JPEG 23 +#define CLK_PCLK_M2MSCALER1 24 +#define CLK_PCLK_M2MSCALER0 25 +#define CLK_PCLK_SMMU_M2MSCALER0 26 +#define CLK_PCLK_SMMU_M2MSCALER1 27 +#define CLK_PCLK_SMMU_JPEG 28 +#define CLK_SCLK_JPEG 29 + +#define MSCL_NR_CLK 30 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 9910b6bbaa7b16cd3a8a7d8be53980fa1b8183a6 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:52 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_MFC domain This patch adds the mux/divider/gate clocks for CMU_MFC domain which generates the clocks for MFC(Multi-Format Codec) IP. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 15 +++ drivers/clk/samsung/clk-exynos5433.c | 113 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 27 ++++- 3 files changed, 154 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index ecb9534c2ea6..0f35167ec15c 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -39,6 +39,8 @@ Required Properties: L2 cache controller. - "samsung,exynos5433-cmu-mscl" - clock controller compatible for CMU_MSCL which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs. + - "samsung,exynos5433-cmu-mfc" - clock controller compatible for CMU_MFC + which generates clocks for MFC(Multi-Format Codec) IP. - reg: physical base address of the controller and length of memory mapped region. @@ -125,6 +127,10 @@ Required Properties: - sclk_jpeg_mscl - aclk_mscl_400 + Input clocks for mfc clock controller: + - oscclk + - aclk_mfc_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -340,6 +346,15 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_MSCL_400>; }; + cmu_mfc: clock-controller@15280000 { + compatible = "samsung,exynos5433-cmu-mfc"; + reg = <0x15280000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_mfc_400"; + clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index d272e42eb48c..40558930711f 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -560,6 +560,9 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFC_400, "aclk_mfc_400", "div_aclk_mfc_400", + ENABLE_ACLK_TOP, 3, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_G2D_266, "aclk_g2d_266", "div_aclk_g2d_266", ENABLE_ACLK_TOP, 2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -3990,3 +3993,113 @@ static void __init exynos5433_cmu_mscl_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl", exynos5433_cmu_mscl_init); + +/* + * Register offset definitions for CMU_MFC + */ +#define MUX_SEL_MFC 0x0200 +#define MUX_ENABLE_MFC 0x0300 +#define MUX_STAT_MFC 0x0400 +#define DIV_MFC 0x0600 +#define DIV_STAT_MFC 0x0700 +#define ENABLE_ACLK_MFC 0x0800 +#define ENABLE_ACLK_MFC_SECURE_SMMU_MFC 0x0804 +#define ENABLE_PCLK_MFC 0x0900 +#define ENABLE_PCLK_MFC_SECURE_SMMU_MFC 0x0904 +#define ENABLE_IP_MFC0 0x0b00 +#define ENABLE_IP_MFC1 0x0b04 +#define ENABLE_IP_MFC_SECURE_SMMU_MFC 0x0b08 + +static unsigned long mfc_clk_regs[] __initdata = { + MUX_SEL_MFC, + MUX_ENABLE_MFC, + MUX_STAT_MFC, + DIV_MFC, + DIV_STAT_MFC, + ENABLE_ACLK_MFC, + ENABLE_ACLK_MFC_SECURE_SMMU_MFC, + ENABLE_PCLK_MFC, + ENABLE_PCLK_MFC_SECURE_SMMU_MFC, + ENABLE_IP_MFC0, + ENABLE_IP_MFC1, + ENABLE_IP_MFC_SECURE_SMMU_MFC, +}; + +PNAME(mout_aclk_mfc_400_user_p) = { "oscclk", "aclk_mfc_400", }; + +static struct samsung_mux_clock mfc_mux_clks[] __initdata = { + /* MUX_SEL_MFC */ + MUX(CLK_MOUT_ACLK_MFC_400_USER, "mout_aclk_mfc_400_user", + mout_aclk_mfc_400_user_p, MUX_SEL_MFC, 0, 0), +}; + +static struct samsung_div_clock mfc_div_clks[] __initdata = { + /* DIV_MFC */ + DIV(CLK_DIV_PCLK_MFC, "div_pclk_mfc", "mout_aclk_mfc_400_user", + DIV_MFC, 0, 2), +}; + +static struct samsung_gate_clock mfc_gate_clks[] __initdata = { + /* ENABLE_ACLK_MFC */ + GATE(CLK_ACLK_BTS_MFC_1, "aclk_bts_mfc_1", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 6, 0, 0), + GATE(CLK_ACLK_BTS_MFC_0, "aclk_bts_mfc_0", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 5, 0, 0), + GATE(CLK_ACLK_AHB2APB_MFCP, "aclk_ahb2apb_mfcp", "div_pclk_mfc", + ENABLE_ACLK_MFC, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_MFCX, "aclk_xiu_mfcx", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFCNP_100, "aclk_mfcnp_100", "div_pclk_mfc", + ENABLE_ACLK_MFC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFCND_400, "aclk_mfcnd_400", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFC, "aclk_mfc", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 0, 0, 0), + + /* ENABLE_ACLK_MFC_SECURE_SMMU_MFC */ + GATE(CLK_ACLK_SMMU_MFC_1, "aclk_smmu_mfc_1", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC_SECURE_SMMU_MFC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_MFC_0, "aclk_smmu_mfc_0", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC_SECURE_SMMU_MFC, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MFC */ + GATE(CLK_PCLK_BTS_MFC_1, "pclk_bts_mfc_1", "div_pclk_mfc", + ENABLE_PCLK_MFC, 4, 0, 0), + GATE(CLK_PCLK_BTS_MFC_0, "pclk_bts_mfc_0", "div_pclk_mfc", + ENABLE_PCLK_MFC, 3, 0, 0), + GATE(CLK_PCLK_PMU_MFC, "pclk_pmu_mfc", "div_pclk_mfc", + ENABLE_PCLK_MFC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_MFC, "pclk_sysreg_mfc", "div_pclk_mfc", + ENABLE_PCLK_MFC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_MFC, "pclk_mfc", "div_pclk_mfc", + ENABLE_PCLK_MFC, 4, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MFC_SECURE_SMMU_MFC */ + GATE(CLK_PCLK_SMMU_MFC_1, "pclk_smmu_mfc_1", "div_pclk_mfc", + ENABLE_PCLK_MFC_SECURE_SMMU_MFC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_MFC_0, "pclk_smmu_mfc_0", "div_pclk_mfc", + ENABLE_PCLK_MFC_SECURE_SMMU_MFC, + 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info mfc_cmu_info __initdata = { + .mux_clks = mfc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mfc_mux_clks), + .div_clks = mfc_div_clks, + .nr_div_clks = ARRAY_SIZE(mfc_div_clks), + .gate_clks = mfc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mfc_gate_clks), + .nr_clk_ids = MFC_NR_CLK, + .clk_regs = mfc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mfc_clk_regs), +}; + +static void __init exynos5433_cmu_mfc_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &mfc_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc", + exynos5433_cmu_mfc_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 9898390710e6..3301ab72c80d 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -153,8 +153,9 @@ #define CLK_ACLK_GSCL_333 233 #define CLK_SCLK_JPEG_MSCL 234 #define CLK_ACLK_MSCL_400 235 +#define CLK_ACLK_MFC_400 236 -#define TOP_NR_CLK 236 +#define TOP_NR_CLK 237 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -976,4 +977,28 @@ #define MSCL_NR_CLK 30 +/* CMU_MFC */ +#define CLK_MOUT_ACLK_MFC_400_USER 1 + +#define CLK_DIV_PCLK_MFC 2 + +#define CLK_ACLK_BTS_MFC_1 3 +#define CLK_ACLK_BTS_MFC_0 4 +#define CLK_ACLK_AHB2APB_MFCP 5 +#define CLK_ACLK_XIU_MFCX 6 +#define CLK_ACLK_MFCNP_100 7 +#define CLK_ACLK_MFCND_400 8 +#define CLK_ACLK_MFC 9 +#define CLK_ACLK_SMMU_MFC_1 10 +#define CLK_ACLK_SMMU_MFC_0 11 +#define CLK_PCLK_BTS_MFC_1 12 +#define CLK_PCLK_BTS_MFC_0 13 +#define CLK_PCLK_PMU_MFC 14 +#define CLK_PCLK_SYSREG_MFC 15 +#define CLK_PCLK_MFC 16 +#define CLK_PCLK_SMMU_MFC_1 17 +#define CLK_PCLK_SMMU_MFC_0 18 + +#define MFC_NR_CLK 19 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 45e58aa5f751fd861d46f7b6d438c1be147458c6 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:53 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_HEVC domain This patch adds the mux/divider/gate clocks for CMU_HEVC domain which generates the clocks for HEVC(High Efficiency Video Codec) decoder IP. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 15 +++ drivers/clk/samsung/clk-exynos5433.c | 115 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 27 ++++- 3 files changed, 156 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 0f35167ec15c..acc1d8aac95c 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -41,6 +41,8 @@ Required Properties: which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs. - "samsung,exynos5433-cmu-mfc" - clock controller compatible for CMU_MFC which generates clocks for MFC(Multi-Format Codec) IP. + - "samsung,exynos5433-cmu-hevc" - clock controller compatible for CMU_HEVC + which generates clocks for HEVC(High Efficiency Video Codec) decoder IP. - reg: physical base address of the controller and length of memory mapped region. @@ -131,6 +133,10 @@ Required Properties: - oscclk - aclk_mfc_400 + Input clocks for hevc clock controller: + - oscclk + - aclk_hevc_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -355,6 +361,15 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>; }; + cmu_hevc: clock-controller@14f80000 { + compatible = "samsung,exynos5433-cmu-hevc"; + reg = <0x14f80000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_hevc_400"; + clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 40558930711f..482a603c7e6b 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -560,6 +560,9 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVC_400, "aclk_hevc_400", "div_aclk_hevc_400", + ENABLE_ACLK_TOP, 5, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_MFC_400, "aclk_mfc_400", "div_aclk_mfc_400", ENABLE_ACLK_TOP, 3, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -4103,3 +4106,115 @@ static void __init exynos5433_cmu_mfc_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc", exynos5433_cmu_mfc_init); + +/* + * Register offset definitions for CMU_HEVC + */ +#define MUX_SEL_HEVC 0x0200 +#define MUX_ENABLE_HEVC 0x0300 +#define MUX_STAT_HEVC 0x0400 +#define DIV_HEVC 0x0600 +#define DIV_STAT_HEVC 0x0700 +#define ENABLE_ACLK_HEVC 0x0800 +#define ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC 0x0804 +#define ENABLE_PCLK_HEVC 0x0900 +#define ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC 0x0904 +#define ENABLE_IP_HEVC0 0x0b00 +#define ENABLE_IP_HEVC1 0x0b04 +#define ENABLE_IP_HEVC_SECURE_SMMU_HEVC 0x0b08 + +static unsigned long hevc_clk_regs[] __initdata = { + MUX_SEL_HEVC, + MUX_ENABLE_HEVC, + MUX_STAT_HEVC, + DIV_HEVC, + DIV_STAT_HEVC, + ENABLE_ACLK_HEVC, + ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC, + ENABLE_PCLK_HEVC, + ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC, + ENABLE_IP_HEVC0, + ENABLE_IP_HEVC1, + ENABLE_IP_HEVC_SECURE_SMMU_HEVC, +}; + +PNAME(mout_aclk_hevc_400_user_p) = { "oscclk", "aclk_hevc_400", }; + +static struct samsung_mux_clock hevc_mux_clks[] __initdata = { + /* MUX_SEL_HEVC */ + MUX(CLK_MOUT_ACLK_HEVC_400_USER, "mout_aclk_hevc_400_user", + mout_aclk_hevc_400_user_p, MUX_SEL_HEVC, 0, 0), +}; + +static struct samsung_div_clock hevc_div_clks[] __initdata = { + /* DIV_HEVC */ + DIV(CLK_DIV_PCLK_HEVC, "div_pclk_hevc", "mout_aclk_hevc_400_user", + DIV_HEVC, 0, 2), +}; + +static struct samsung_gate_clock hevc_gate_clks[] __initdata = { + /* ENABLE_ACLK_HEVC */ + GATE(CLK_ACLK_BTS_HEVC_1, "aclk_bts_hevc_1", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 6, 0, 0), + GATE(CLK_ACLK_BTS_HEVC_0, "aclk_bts_hevc_0", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 5, 0, 0), + GATE(CLK_ACLK_AHB2APB_HEVCP, "aclk_ahb2apb_hevcp", "div_pclk_hevc", + ENABLE_ACLK_HEVC, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_HEVCX, "aclk_xiu_hevcx", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVCNP_100, "aclk_hevcnp_100", "div_pclk_hevc", + ENABLE_ACLK_HEVC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVCND_400, "aclk_hevcnd_400", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVC, "aclk_hevc", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 0, 0, 0), + + /* ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC */ + GATE(CLK_ACLK_SMMU_HEVC_1, "aclk_smmu_hevc_1", + "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_HEVC_0, "aclk_smmu_hevc_0", + "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_HEVC */ + GATE(CLK_PCLK_BTS_HEVC_1, "pclk_bts_hevc_1", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 4, 0, 0), + GATE(CLK_PCLK_BTS_HEVC_0, "pclk_bts_hevc_0", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 3, 0, 0), + GATE(CLK_PCLK_PMU_HEVC, "pclk_pmu_hevc", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_HEVC, "pclk_sysreg_hevc", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_HEVC, "pclk_hevc", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 4, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC */ + GATE(CLK_PCLK_SMMU_HEVC_1, "pclk_smmu_hevc_1", "div_pclk_hevc", + ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_HEVC_0, "pclk_smmu_hevc_0", "div_pclk_hevc", + ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC, + 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info hevc_cmu_info __initdata = { + .mux_clks = hevc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(hevc_mux_clks), + .div_clks = hevc_div_clks, + .nr_div_clks = ARRAY_SIZE(hevc_div_clks), + .gate_clks = hevc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(hevc_gate_clks), + .nr_clk_ids = HEVC_NR_CLK, + .clk_regs = hevc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(hevc_clk_regs), +}; + +static void __init exynos5433_cmu_hevc_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &hevc_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc", + exynos5433_cmu_hevc_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 3301ab72c80d..1b2d333c1786 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -154,8 +154,9 @@ #define CLK_SCLK_JPEG_MSCL 234 #define CLK_ACLK_MSCL_400 235 #define CLK_ACLK_MFC_400 236 +#define CLK_ACLK_HEVC_400 237 -#define TOP_NR_CLK 237 +#define TOP_NR_CLK 238 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1001,4 +1002,28 @@ #define MFC_NR_CLK 19 +/* CMU_HEVC */ +#define CLK_MOUT_ACLK_HEVC_400_USER 1 + +#define CLK_DIV_PCLK_HEVC 2 + +#define CLK_ACLK_BTS_HEVC_1 3 +#define CLK_ACLK_BTS_HEVC_0 4 +#define CLK_ACLK_AHB2APB_HEVCP 5 +#define CLK_ACLK_XIU_HEVCX 6 +#define CLK_ACLK_HEVCNP_100 7 +#define CLK_ACLK_HEVCND_400 8 +#define CLK_ACLK_HEVC 9 +#define CLK_ACLK_SMMU_HEVC_1 10 +#define CLK_ACLK_SMMU_HEVC_0 11 +#define CLK_PCLK_BTS_HEVC_1 12 +#define CLK_PCLK_BTS_HEVC_0 13 +#define CLK_PCLK_PMU_HEVC 14 +#define CLK_PCLK_SYSREG_HEVC 15 +#define CLK_PCLK_HEVC 16 +#define CLK_PCLK_SMMU_HEVC_1 17 +#define CLK_PCLK_SMMU_HEVC_0 18 + +#define HEVC_NR_CLK 19 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 8e46c4b84faf317773d5a4ec6d807ceae2d0eb41 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:54 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_ISP domain This patch adds the mux/divider/gate clocks for CMU_ISP domain which generates the clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 20 ++ drivers/clk/samsung/clk-exynos5433.c | 267 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 89 ++++++- 3 files changed, 375 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index acc1d8aac95c..4f3bfcd366a3 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -43,6 +43,8 @@ Required Properties: which generates clocks for MFC(Multi-Format Codec) IP. - "samsung,exynos5433-cmu-hevc" - clock controller compatible for CMU_HEVC which generates clocks for HEVC(High Efficiency Video Codec) decoder IP. + - "samsung,exynos5433-cmu-isp" - clock controller compatible for CMU_ISP + which generates clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -137,6 +139,11 @@ Required Properties: - oscclk - aclk_hevc_400 + Input clocks for isp clock controller: + - oscclk + - aclk_isp_dis_400 + - aclk_isp_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -370,6 +377,19 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>; }; + cmu_isp: clock-controller@146d0000 { + compatible = "samsung,exynos5433-cmu-isp"; + reg = <0x146d0000 0x0b0c>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_isp_dis_400", + "aclk_isp_400"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_ISP_DIS_400>, + <&cmu_top CLK_ACLK_ISP_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 482a603c7e6b..a8ea6e1fbffc 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -404,6 +404,12 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { }; static struct samsung_div_clock top_div_clks[] __initdata = { + /* DIV_TOP0 */ + DIV(CLK_DIV_ACLK_ISP_DIS_400, "div_aclk_isp_dis_400", + "mout_aclk_isp_dis_400", DIV_TOP0, 4, 4), + DIV(CLK_DIV_ACLK_ISP_400, "div_aclk_isp_400", + "mout_aclk_isp_400", DIV_TOP0, 0, 4), + /* DIV_TOP1 */ DIV(CLK_DIV_ACLK_GSCL_111, "div_aclk_gscl_111", "mout_aclk_gscl_333", DIV_TOP1, 28, 3), @@ -560,6 +566,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ISP_DIS_400, "aclk_isp_dis_400", "div_aclk_isp_dis_400", + ENABLE_ACLK_TOP, 7, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ISP_400, "aclk_isp_400", "div_aclk_isp_400", + ENABLE_ACLK_TOP, 6, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_HEVC_400, "aclk_hevc_400", "div_aclk_hevc_400", ENABLE_ACLK_TOP, 5, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -4218,3 +4230,258 @@ static void __init exynos5433_cmu_hevc_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc", exynos5433_cmu_hevc_init); + +/* + * Register offset definitions for CMU_ISP + */ +#define MUX_SEL_ISP 0x0200 +#define MUX_ENABLE_ISP 0x0300 +#define MUX_STAT_ISP 0x0400 +#define DIV_ISP 0x0600 +#define DIV_STAT_ISP 0x0700 +#define ENABLE_ACLK_ISP0 0x0800 +#define ENABLE_ACLK_ISP1 0x0804 +#define ENABLE_ACLK_ISP2 0x0808 +#define ENABLE_PCLK_ISP 0x0900 +#define ENABLE_SCLK_ISP 0x0a00 +#define ENABLE_IP_ISP0 0x0b00 +#define ENABLE_IP_ISP1 0x0b04 +#define ENABLE_IP_ISP2 0x0b08 +#define ENABLE_IP_ISP3 0x0b0c + +static unsigned long isp_clk_regs[] __initdata = { + MUX_SEL_ISP, + MUX_ENABLE_ISP, + MUX_STAT_ISP, + DIV_ISP, + DIV_STAT_ISP, + ENABLE_ACLK_ISP0, + ENABLE_ACLK_ISP1, + ENABLE_ACLK_ISP2, + ENABLE_PCLK_ISP, + ENABLE_SCLK_ISP, + ENABLE_IP_ISP0, + ENABLE_IP_ISP1, + ENABLE_IP_ISP2, + ENABLE_IP_ISP3, +}; + +PNAME(mout_aclk_isp_dis_400_user_p) = { "oscclk", "aclk_isp_dis_400", }; +PNAME(mout_aclk_isp_400_user_p) = { "oscclk", "aclk_isp_400", }; + +static struct samsung_mux_clock isp_mux_clks[] __initdata = { + /* MUX_SEL_ISP */ + MUX(CLK_MOUT_ACLK_ISP_DIS_400_USER, "mout_aclk_isp_dis_400_user", + mout_aclk_isp_dis_400_user_p, MUX_SEL_ISP, 4, 0), + MUX(CLK_MOUT_ACLK_ISP_400_USER, "mout_aclk_isp_400_user", + mout_aclk_isp_400_user_p, MUX_SEL_ISP, 0, 0), +}; + +static struct samsung_div_clock isp_div_clks[] __initdata = { + /* DIV_ISP */ + DIV(CLK_DIV_PCLK_ISP_DIS, "div_pclk_isp_dis", + "mout_aclk_isp_dis_400_user", DIV_ISP, 12, 3), + DIV(CLK_DIV_PCLK_ISP, "div_pclk_isp", "mout_aclk_isp_400_user", + DIV_ISP, 8, 3), + DIV(CLK_DIV_ACLK_ISP_D_200, "div_aclk_isp_d_200", + "mout_aclk_isp_400_user", DIV_ISP, 4, 3), + DIV(CLK_DIV_ACLK_ISP_C_200, "div_aclk_isp_c_200", + "mout_aclk_isp_400_user", DIV_ISP, 0, 3), +}; + +static struct samsung_gate_clock isp_gate_clks[] __initdata = { + /* ENABLE_ACLK_ISP0 */ + GATE(CLK_ACLK_ISP_D_GLUE, "aclk_isp_d_glue", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SCALERP, "aclk_scalerp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 5, 0, 0), + GATE(CLK_ACLK_3DNR, "aclk_3dnr", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 4, 0, 0), + GATE(CLK_ACLK_DIS, "aclk_dis", "mout_aclk_isp_dis_400_user", + ENABLE_ACLK_ISP0, 3, 0, 0), + GATE(CLK_ACLK_SCALERC, "aclk_scalerc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 2, 0, 0), + GATE(CLK_ACLK_DRC, "aclk_drc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 1, 0, 0), + GATE(CLK_ACLK_ISP, "aclk_isp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 0, 0, 0), + + /* ENABLE_ACLK_ISP1 */ + GATE(CLK_ACLK_AXIUS_SCALERP, "aclk_axius_scalerp", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_SCALERC, "aclk_axius_scalerc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_DRC, "aclk_axius_drc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBM_ISP2P, "aclk_asyncahbm_isp2p", + "div_pclk_isp", ENABLE_ACLK_ISP1, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBM_ISP1P, "aclk_asyncahbm_isp1p", + "div_pclk_isp", ENABLE_ACLK_ISP1, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DIS1, "aclk_asyncaxis_dis1", + "mout_aclk_isp_dis_400_user", ENABLE_ACLK_ISP1, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DIS0, "aclk_asyncaxis_dis0", + "mout_aclk_isp_dis_400_user", ENABLE_ACLK_ISP1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DIS1, "aclk_asyncaxim_dis1", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DIS0, "aclk_asyncaxim_dis0", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP2P, "aclk_asyncaxim_isp2p", + "div_aclk_isp_d_200", ENABLE_ACLK_ISP1, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP1P, "aclk_asyncaxim_isp1p", + "div_aclk_isp_c_200", ENABLE_ACLK_ISP1, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP2P, "aclk_ahb2apb_isp2p", "div_pclk_isp", + ENABLE_ACLK_ISP1, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP1P, "aclk_ahb2apb_isp1p", "div_pclk_isp", + ENABLE_ACLK_ISP1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP2P, "aclk_axi2apb_isp2p", + "div_aclk_isp_d_200", ENABLE_ACLK_ISP1, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP1P, "aclk_axi2apb_isp1p", + "div_aclk_isp_c_200", ENABLE_ACLK_ISP1, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPEX1, "aclk_xiu_ispex1", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPEX0, "aclk_xiu_ispex0", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ISPND_400, "aclk_ispnd_400", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP1, 1, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_ISP2 */ + GATE(CLK_ACLK_SMMU_SCALERP, "aclk_smmu_scalerp", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_3DNR, "aclk_smmu_3dnr", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_DIS1, "aclk_smmu_dis1", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_DIS0, "aclk_smmu_dis0", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_SCALERC, "aclk_smmu_scalerc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_DRC, "aclk_smmu_drc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_ISP, "aclk_smmu_isp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_SCALERP, "aclk_bts_scalerp", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_3DR, "aclk_bts_3dnr", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_DIS1, "aclk_bts_dis1", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_DIS0, "aclk_bts_dis0", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_SCALERC, "aclk_bts_scalerc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_DRC, "aclk_bts_drc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_ISP, "aclk_bts_isp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_ISP */ + GATE(CLK_PCLK_SMMU_SCALERP, "pclk_smmu_scalerp", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_3DNR, "pclk_smmu_3dnr", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_DIS1, "pclk_smmu_dis1", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_DIS0, "pclk_smmu_dis0", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_SCALERC, "pclk_smmu_scalerc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_DRC, "pclk_smmu_drc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_ISP, "pclk_smmu_isp", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_SCALERP, "pclk_bts_scalerp", "div_pclk_isp", + ENABLE_PCLK_ISP, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_3DNR, "pclk_bts_3dnr", "div_pclk_isp", + ENABLE_PCLK_ISP, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_DIS1, "pclk_bts_dis1", "div_pclk_isp", + ENABLE_PCLK_ISP, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_DIS0, "pclk_bts_dis0", "div_pclk_isp", + ENABLE_PCLK_ISP, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_SCALERC, "pclk_bts_scalerc", "div_pclk_isp", + ENABLE_PCLK_ISP, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_DRC, "pclk_bts_drc", "div_pclk_isp", + ENABLE_PCLK_ISP, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_ISP, "pclk_bts_isp", "div_pclk_isp", + ENABLE_PCLK_ISP, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_DIS1, "pclk_asyncaxi_dis1", "div_pclk_isp", + ENABLE_PCLK_ISP, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_DIS0, "pclk_asyncaxi_dis0", "div_pclk_isp", + ENABLE_PCLK_ISP, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_ISP, "pclk_pmu_isp", "div_pclk_isp", + ENABLE_PCLK_ISP, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_ISP, "pclk_sysreg_isp", "div_pclk_isp", + ENABLE_PCLK_ISP, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CMU_ISP_LOCAL, "pclk_cmu_isp_local", + "div_aclk_isp_c_200", ENABLE_PCLK_ISP, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SCALERP, "pclk_scalerp", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_3DNR, "pclk_3dnr", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DIS_CORE, "pclk_dis_core", "div_pclk_isp_dis", + ENABLE_PCLK_ISP, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DIS, "pclk_dis", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SCALERC, "pclk_scalerc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DRC, "pclk_drc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP, "pclk_isp", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_ISP */ + GATE(CLK_SCLK_PIXELASYNCS_DIS, "sclk_pixelasyncs_dis", + "mout_aclk_isp_dis_400_user", ENABLE_SCLK_ISP, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCM_DIS, "sclk_pixelasyncm_dis", + "mout_aclk_isp_dis_400_user", ENABLE_SCLK_ISP, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCS_SCALERP, "sclk_pixelasyncs_scalerp", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCM_ISPD, "sclk_pixelasyncm_ispd", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCS_ISPC, "sclk_pixelasyncs_ispc", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCM_ISPC, "sclk_pixelasyncm_ispc", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info isp_cmu_info __initdata = { + .mux_clks = isp_mux_clks, + .nr_mux_clks = ARRAY_SIZE(isp_mux_clks), + .div_clks = isp_div_clks, + .nr_div_clks = ARRAY_SIZE(isp_div_clks), + .gate_clks = isp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(isp_gate_clks), + .nr_clk_ids = ISP_NR_CLK, + .clk_regs = isp_clk_regs, + .nr_clk_regs = ARRAY_SIZE(isp_clk_regs), +}; + +static void __init exynos5433_cmu_isp_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &isp_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp", + exynos5433_cmu_isp_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 1b2d333c1786..fbc81e3424a6 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -116,6 +116,8 @@ #define CLK_DIV_SCLK_USBDRD30 143 #define CLK_DIV_SCLK_JPEG 144 #define CLK_DIV_ACLK_MSCL_400 145 +#define CLK_DIV_ACLK_ISP_DIS_400 146 +#define CLK_DIV_ACLK_ISP_400 147 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -155,8 +157,10 @@ #define CLK_ACLK_MSCL_400 235 #define CLK_ACLK_MFC_400 236 #define CLK_ACLK_HEVC_400 237 +#define CLK_ACLK_ISP_DIS_400 238 +#define CLK_ACLK_ISP_400 239 -#define TOP_NR_CLK 238 +#define TOP_NR_CLK 240 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1026,4 +1030,87 @@ #define HEVC_NR_CLK 19 +/* CMU_ISP */ +#define CLK_MOUT_ACLK_ISP_DIS_400_USER 1 +#define CLK_MOUT_ACLK_ISP_400_USER 2 + +#define CLK_DIV_PCLK_ISP_DIS 3 +#define CLK_DIV_PCLK_ISP 4 +#define CLK_DIV_ACLK_ISP_D_200 5 +#define CLK_DIV_ACLK_ISP_C_200 6 + +#define CLK_ACLK_ISP_D_GLUE 7 +#define CLK_ACLK_SCALERP 8 +#define CLK_ACLK_3DNR 9 +#define CLK_ACLK_DIS 10 +#define CLK_ACLK_SCALERC 11 +#define CLK_ACLK_DRC 12 +#define CLK_ACLK_ISP 13 +#define CLK_ACLK_AXIUS_SCALERP 14 +#define CLK_ACLK_AXIUS_SCALERC 15 +#define CLK_ACLK_AXIUS_DRC 16 +#define CLK_ACLK_ASYNCAHBM_ISP2P 17 +#define CLK_ACLK_ASYNCAHBM_ISP1P 18 +#define CLK_ACLK_ASYNCAXIS_DIS1 19 +#define CLK_ACLK_ASYNCAXIS_DIS0 20 +#define CLK_ACLK_ASYNCAXIM_DIS1 21 +#define CLK_ACLK_ASYNCAXIM_DIS0 22 +#define CLK_ACLK_ASYNCAXIM_ISP2P 23 +#define CLK_ACLK_ASYNCAXIM_ISP1P 24 +#define CLK_ACLK_AHB2APB_ISP2P 25 +#define CLK_ACLK_AHB2APB_ISP1P 26 +#define CLK_ACLK_AXI2APB_ISP2P 27 +#define CLK_ACLK_AXI2APB_ISP1P 28 +#define CLK_ACLK_XIU_ISPEX1 29 +#define CLK_ACLK_XIU_ISPEX0 30 +#define CLK_ACLK_ISPND_400 31 +#define CLK_ACLK_SMMU_SCALERP 32 +#define CLK_ACLK_SMMU_3DNR 33 +#define CLK_ACLK_SMMU_DIS1 34 +#define CLK_ACLK_SMMU_DIS0 35 +#define CLK_ACLK_SMMU_SCALERC 36 +#define CLK_ACLK_SMMU_DRC 37 +#define CLK_ACLK_SMMU_ISP 38 +#define CLK_ACLK_BTS_SCALERP 39 +#define CLK_ACLK_BTS_3DR 40 +#define CLK_ACLK_BTS_DIS1 41 +#define CLK_ACLK_BTS_DIS0 42 +#define CLK_ACLK_BTS_SCALERC 43 +#define CLK_ACLK_BTS_DRC 44 +#define CLK_ACLK_BTS_ISP 45 +#define CLK_PCLK_SMMU_SCALERP 46 +#define CLK_PCLK_SMMU_3DNR 47 +#define CLK_PCLK_SMMU_DIS1 48 +#define CLK_PCLK_SMMU_DIS0 49 +#define CLK_PCLK_SMMU_SCALERC 50 +#define CLK_PCLK_SMMU_DRC 51 +#define CLK_PCLK_SMMU_ISP 52 +#define CLK_PCLK_BTS_SCALERP 53 +#define CLK_PCLK_BTS_3DNR 54 +#define CLK_PCLK_BTS_DIS1 55 +#define CLK_PCLK_BTS_DIS0 56 +#define CLK_PCLK_BTS_SCALERC 57 +#define CLK_PCLK_BTS_DRC 58 +#define CLK_PCLK_BTS_ISP 59 +#define CLK_PCLK_ASYNCAXI_DIS1 60 +#define CLK_PCLK_ASYNCAXI_DIS0 61 +#define CLK_PCLK_PMU_ISP 62 +#define CLK_PCLK_SYSREG_ISP 63 +#define CLK_PCLK_CMU_ISP_LOCAL 64 +#define CLK_PCLK_SCALERP 65 +#define CLK_PCLK_3DNR 66 +#define CLK_PCLK_DIS_CORE 67 +#define CLK_PCLK_DIS 68 +#define CLK_PCLK_SCALERC 69 +#define CLK_PCLK_DRC 70 +#define CLK_PCLK_ISP 71 +#define CLK_SCLK_PIXELASYNCS_DIS 72 +#define CLK_SCLK_PIXELASYNCM_DIS 73 +#define CLK_SCLK_PIXELASYNCS_SCALERP 74 +#define CLK_SCLK_PIXELASYNCM_ISPD 75 +#define CLK_SCLK_PIXELASYNCS_ISPC 76 +#define CLK_SCLK_PIXELASYNCM_ISPC 77 + +#define ISP_NR_CLK 78 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 6958f22f39f9292f6e871b4383a11f183c1271ed Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:55 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_CAM0 domain This patch adds the mux/divider/gate clocks for CMU_CAM0 domain which generates the clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1} IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 24 + drivers/clk/samsung/clk-exynos5433.c | 501 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 146 +++++- 3 files changed, 670 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 4f3bfcd366a3..84002e4b52e5 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -45,6 +45,9 @@ Required Properties: which generates clocks for HEVC(High Efficiency Video Codec) decoder IP. - "samsung,exynos5433-cmu-isp" - clock controller compatible for CMU_ISP which generates clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs. + - "samsung,exynos5433-cmu-cam0" - clock controller compatible for CMU_CAM0 + which generates clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1} + IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -144,6 +147,12 @@ Required Properties: - aclk_isp_dis_400 - aclk_isp_400 + Input clocks for cam0 clock controller: + - oscclk + - aclk_cam0_333 + - aclk_cam0_400 + - aclk_cam0_552 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -390,6 +399,21 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_ISP_400>; }; + cmu_cam0: clock-controller@120d0000 { + compatible = "samsung,exynos5433-cmu-cam0"; + reg = <0x120d0000 0x0b0c>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_cam0_333", + "aclk_cam0_400", + "aclk_cam0_552"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_CAM0_333>, + <&cmu_top CLK_ACLK_CAM0_400>, + <&cmu_top CLK_ACLK_CAM0_552>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index a8ea6e1fbffc..ce6487375670 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -405,6 +405,12 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { static struct samsung_div_clock top_div_clks[] __initdata = { /* DIV_TOP0 */ + DIV(CLK_DIV_ACLK_CAM0_333, "div_aclk_cam0_333", "mout_mfc_pll_user", + DIV_TOP0, 16, 3), + DIV(CLK_DIV_ACLK_CAM0_400, "div_aclk_cam0_400", "mout_bus_pll_user", + DIV_TOP0, 12, 3), + DIV(CLK_DIV_ACLK_CAM0_552, "div_aclk_cam0_552", "mout_isp_pll", + DIV_TOP0, 8, 3), DIV(CLK_DIV_ACLK_ISP_DIS_400, "div_aclk_isp_dis_400", "mout_aclk_isp_dis_400", DIV_TOP0, 4, 4), DIV(CLK_DIV_ACLK_ISP_400, "div_aclk_isp_400", @@ -566,6 +572,15 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0_333, "aclk_cam0_333", "div_aclk_cam0_333", + ENABLE_ACLK_TOP, 10, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0_400, "aclk_cam0_400", "div_aclk_cam0_400", + ENABLE_ACLK_TOP, 9, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0_552, "aclk_cam0_552", "div_aclk_cam0_552", + ENABLE_ACLK_TOP, 8, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_ISP_DIS_400, "aclk_isp_dis_400", "div_aclk_isp_dis_400", ENABLE_ACLK_TOP, 7, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -4485,3 +4500,489 @@ static void __init exynos5433_cmu_isp_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp", exynos5433_cmu_isp_init); + +/* + * Register offset definitions for CMU_CAM0 + */ +#define MUX_SEL_CAM00 0x0200 +#define MUX_SEL_CAM01 0x0204 +#define MUX_SEL_CAM02 0x0208 +#define MUX_SEL_CAM03 0x020c +#define MUX_SEL_CAM04 0x0210 +#define MUX_ENABLE_CAM00 0x0300 +#define MUX_ENABLE_CAM01 0x0304 +#define MUX_ENABLE_CAM02 0x0308 +#define MUX_ENABLE_CAM03 0x030c +#define MUX_ENABLE_CAM04 0x0310 +#define MUX_STAT_CAM00 0x0400 +#define MUX_STAT_CAM01 0x0404 +#define MUX_STAT_CAM02 0x0408 +#define MUX_STAT_CAM03 0x040c +#define MUX_STAT_CAM04 0x0410 +#define MUX_IGNORE_CAM01 0x0504 +#define DIV_CAM00 0x0600 +#define DIV_CAM01 0x0604 +#define DIV_CAM02 0x0608 +#define DIV_CAM03 0x060c +#define DIV_STAT_CAM00 0x0700 +#define DIV_STAT_CAM01 0x0704 +#define DIV_STAT_CAM02 0x0708 +#define DIV_STAT_CAM03 0x070c +#define ENABLE_ACLK_CAM00 0X0800 +#define ENABLE_ACLK_CAM01 0X0804 +#define ENABLE_ACLK_CAM02 0X0808 +#define ENABLE_PCLK_CAM0 0X0900 +#define ENABLE_SCLK_CAM0 0X0a00 +#define ENABLE_IP_CAM00 0X0b00 +#define ENABLE_IP_CAM01 0X0b04 +#define ENABLE_IP_CAM02 0X0b08 +#define ENABLE_IP_CAM03 0X0b0C + +static unsigned long cam0_clk_regs[] __initdata = { + MUX_SEL_CAM00, + MUX_SEL_CAM01, + MUX_SEL_CAM02, + MUX_SEL_CAM03, + MUX_SEL_CAM04, + MUX_ENABLE_CAM00, + MUX_ENABLE_CAM01, + MUX_ENABLE_CAM02, + MUX_ENABLE_CAM03, + MUX_ENABLE_CAM04, + MUX_STAT_CAM00, + MUX_STAT_CAM01, + MUX_STAT_CAM02, + MUX_STAT_CAM03, + MUX_STAT_CAM04, + MUX_IGNORE_CAM01, + DIV_CAM00, + DIV_CAM01, + DIV_CAM02, + DIV_CAM03, + DIV_STAT_CAM00, + DIV_STAT_CAM01, + DIV_STAT_CAM02, + DIV_STAT_CAM03, + ENABLE_ACLK_CAM00, + ENABLE_ACLK_CAM01, + ENABLE_ACLK_CAM02, + ENABLE_PCLK_CAM0, + ENABLE_SCLK_CAM0, + ENABLE_IP_CAM00, + ENABLE_IP_CAM01, + ENABLE_IP_CAM02, + ENABLE_IP_CAM03, +}; +PNAME(mout_aclk_cam0_333_user_p) = { "oscclk", "aclk_cam0_333", }; +PNAME(mout_aclk_cam0_400_user_p) = { "oscclk", "aclk_cam0_400", }; +PNAME(mout_aclk_cam0_552_user_p) = { "oscclk", "aclk_cam0_552", }; + +PNAME(mout_phyclk_rxbyteclkhs0_s4_user_p) = { "oscclk", + "phyclk_rxbyteclkhs0_s4_phy", }; +PNAME(mout_phyclk_rxbyteclkhs0_s2a_user_p) = { "oscclk", + "phyclk_rxbyteclkhs0_s2a_phy", }; + +PNAME(mout_aclk_lite_d_b_p) = { "mout_aclk_lite_d_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_lite_d_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_lite_b_b_p) = { "mout_aclk_lite_b_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_lite_b_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_lite_a_b_p) = { "mout_aclk_lite_a_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_lite_a_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_cam0_400_p) = { "mout_aclk_cam0_400_user", + "mout_aclk_cam0_333_user", }; + +PNAME(mout_aclk_csis1_b_p) = { "mout_aclk_csis1_a", + "mout_aclk_cam0_333_user" }; +PNAME(mout_aclk_csis1_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_csis0_b_p) = { "mout_aclk_csis0_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_csis0_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk-cam0_400_user", }; +PNAME(mout_aclk_3aa1_b_p) = { "mout_aclk_3aa1_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_3aa1_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_3aa0_b_p) = { "mout_aclk_3aa0_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_3aa0_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; + +PNAME(mout_sclk_lite_freecnt_c_p) = { "mout_sclk_lite_freecnt_b", + "div_pclk_lite_d", }; +PNAME(mout_sclk_lite_freecnt_b_p) = { "mout_sclk_lite_freecnt_a", + "div_pclk_pixelasync_lite_c", }; +PNAME(mout_sclk_lite_freecnt_a_p) = { "div_pclk_lite_a", + "div_pclk_lite_b", }; +PNAME(mout_sclk_pixelasync_lite_c_b_p) = { "mout_sclk_pixelasync_lite_c_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_sclk_pixelasync_lite_c_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_sclk_pixelasync_lite_c_init_b_p) = { + "mout_sclk_pixelasync_lite_c_init_a", + "mout_aclk_cam0_400_user", }; +PNAME(mout_sclk_pixelasync_lite_c_init_a_p) = { + "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; + +static struct samsung_fixed_rate_clock cam0_fixed_clks[] __initdata = { + FRATE(CLK_PHYCLK_RXBYTEECLKHS0_S4_PHY, "phyclk_rxbyteclkhs0_s4_phy", + NULL, CLK_IS_ROOT, 100000000), + FRATE(CLK_PHYCLK_RXBYTEECLKHS0_S2A_PHY, "phyclk_rxbyteclkhs0_s2a_phy", + NULL, CLK_IS_ROOT, 100000000), +}; + +static struct samsung_mux_clock cam0_mux_clks[] __initdata = { + /* MUX_SEL_CAM00 */ + MUX(CLK_MOUT_ACLK_CAM0_333_USER, "mout_aclk_cam0_333_user", + mout_aclk_cam0_333_user_p, MUX_SEL_CAM00, 8, 1), + MUX(CLK_MOUT_ACLK_CAM0_400_USER, "mout_aclk_cam0_400_user", + mout_aclk_cam0_400_user_p, MUX_SEL_CAM00, 4, 1), + MUX(CLK_MOUT_ACLK_CAM0_552_USER, "mout_aclk_cam0_552_user", + mout_aclk_cam0_552_user_p, MUX_SEL_CAM00, 0, 1), + + /* MUX_SEL_CAM01 */ + MUX(CLK_MOUT_PHYCLK_RXBYTECLKHS0_S4_USER, + "mout_phyclk_rxbyteclkhs0_s4_user", + mout_phyclk_rxbyteclkhs0_s4_user_p, + MUX_SEL_CAM01, 4, 1), + MUX(CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2A_USER, + "mout_phyclk_rxbyteclkhs0_s2a_user", + mout_phyclk_rxbyteclkhs0_s2a_user_p, + MUX_SEL_CAM01, 0, 1), + + /* MUX_SEL_CAM02 */ + MUX(CLK_MOUT_ACLK_LITE_D_B, "mout_aclk_lite_d_b", mout_aclk_lite_d_b_p, + MUX_SEL_CAM02, 24, 1), + MUX(CLK_MOUT_ACLK_LITE_D_A, "mout_aclk_lite_d_a", mout_aclk_lite_d_a_p, + MUX_SEL_CAM02, 20, 1), + MUX(CLK_MOUT_ACLK_LITE_B_B, "mout_aclk_lite_b_b", mout_aclk_lite_b_b_p, + MUX_SEL_CAM02, 16, 1), + MUX(CLK_MOUT_ACLK_LITE_B_A, "mout_aclk_lite_b_a", mout_aclk_lite_b_a_p, + MUX_SEL_CAM02, 12, 1), + MUX(CLK_MOUT_ACLK_LITE_A_B, "mout_aclk_lite_a_b", mout_aclk_lite_a_b_p, + MUX_SEL_CAM02, 8, 1), + MUX(CLK_MOUT_ACLK_LITE_A_A, "mout_aclk_lite_a_a", mout_aclk_lite_a_a_p, + MUX_SEL_CAM02, 4, 1), + MUX(CLK_MOUT_ACLK_CAM0_400, "mout_aclk_cam0_400", mout_aclk_cam0_400_p, + MUX_SEL_CAM02, 0, 1), + + /* MUX_SEL_CAM03 */ + MUX(CLK_MOUT_ACLK_CSIS1_B, "mout_aclk_csis1_b", mout_aclk_csis1_b_p, + MUX_SEL_CAM03, 28, 1), + MUX(CLK_MOUT_ACLK_CSIS1_A, "mout_aclk_csis1_a", mout_aclk_csis1_a_p, + MUX_SEL_CAM03, 24, 1), + MUX(CLK_MOUT_ACLK_CSIS0_B, "mout_aclk_csis0_b", mout_aclk_csis0_b_p, + MUX_SEL_CAM03, 20, 1), + MUX(CLK_MOUT_ACLK_CSIS0_A, "mout_aclk_csis0_a", mout_aclk_csis0_a_p, + MUX_SEL_CAM03, 16, 1), + MUX(CLK_MOUT_ACLK_3AA1_B, "mout_aclk_3aa1_b", mout_aclk_3aa1_b_p, + MUX_SEL_CAM03, 12, 1), + MUX(CLK_MOUT_ACLK_3AA1_A, "mout_aclk_3aa1_a", mout_aclk_3aa1_a_p, + MUX_SEL_CAM03, 8, 1), + MUX(CLK_MOUT_ACLK_3AA0_B, "mout_aclk_3aa0_b", mout_aclk_3aa0_b_p, + MUX_SEL_CAM03, 4, 1), + MUX(CLK_MOUT_ACLK_3AA0_A, "mout_aclk_3aa0_a", mout_aclk_3aa0_a_p, + MUX_SEL_CAM03, 0, 1), + + /* MUX_SEL_CAM04 */ + MUX(CLK_MOUT_SCLK_LITE_FREECNT_C, "mout_sclk_lite_freecnt_c", + mout_sclk_lite_freecnt_c_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_LITE_FREECNT_B, "mout_sclk_lite_freecnt_b", + mout_sclk_lite_freecnt_b_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_LITE_FREECNT_A, "mout_sclk_lite_freecnt_a", + mout_sclk_lite_freecnt_a_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_B, "mout_sclk_pixelasync_lite_c_b", + mout_sclk_pixelasync_lite_c_b_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_A, "mout_sclk_pixelasync_lite_c_a", + mout_sclk_pixelasync_lite_c_a_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_B, + "mout_sclk_pixelasync_lite_c_init_b", + mout_sclk_pixelasync_lite_c_init_b_p, + MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_A, + "mout_sclk_pixelasync_lite_c_init_a", + mout_sclk_pixelasync_lite_c_init_a_p, + MUX_SEL_CAM04, 24, 1), +}; + +static struct samsung_div_clock cam0_div_clks[] __initdata = { + /* DIV_CAM00 */ + DIV(CLK_DIV_PCLK_CAM0_50, "div_pclk_cam0_50", "div_aclk_cam0_200", + DIV_CAM00, 8, 2), + DIV(CLK_DIV_ACLK_CAM0_200, "div_aclk_cam0_200", "mout_aclk_cam0_400", + DIV_CAM00, 4, 3), + DIV(CLK_DIV_ACLK_CAM0_BUS_400, "div_aclk_cam0_bus_400", + "mout_aclk_cam0_400", DIV_CAM00, 0, 3), + + /* DIV_CAM01 */ + DIV(CLK_DIV_PCLK_LITE_D, "div_pclk_lite_d", "div_aclk_lite_d", + DIV_CAM01, 20, 2), + DIV(CLK_DIV_ACLK_LITE_D, "div_aclk_lite_d", "mout_aclk_lite_d_b", + DIV_CAM01, 16, 3), + DIV(CLK_DIV_PCLK_LITE_B, "div_pclk_lite_b", "div_aclk_lite_b", + DIV_CAM01, 12, 2), + DIV(CLK_DIV_ACLK_LITE_B, "div_aclk_lite_b", "mout_aclk_lite_b_b", + DIV_CAM01, 8, 3), + DIV(CLK_DIV_PCLK_LITE_A, "div_pclk_lite_a", "div_aclk_lite_a", + DIV_CAM01, 4, 2), + DIV(CLK_DIV_ACLK_LITE_A, "div_aclk_lite_a", "mout_aclk_lite_a_b", + DIV_CAM01, 0, 3), + + /* DIV_CAM02 */ + DIV(CLK_DIV_ACLK_CSIS1, "div_aclk_csis1", "mout_aclk_csis1_b", + DIV_CAM02, 20, 3), + DIV(CLK_DIV_ACLK_CSIS0, "div_aclk_csis0", "mout_aclk_csis0_b", + DIV_CAM02, 16, 3), + DIV(CLK_DIV_PCLK_3AA1, "div_pclk_3aa1", "div_aclk_3aa1", + DIV_CAM02, 12, 2), + DIV(CLK_DIV_ACLK_3AA1, "div_aclk_3aa1", "mout_aclk_3aa1_b", + DIV_CAM02, 8, 3), + DIV(CLK_DIV_PCLK_3AA0, "div_pclk_3aa0", "div_aclk_3aa0", + DIV_CAM02, 4, 2), + DIV(CLK_DIV_ACLK_3AA0, "div_aclk_3aa0", "mout_aclk_3aa0_b", + DIV_CAM02, 0, 3), + + /* DIV_CAM03 */ + DIV(CLK_DIV_SCLK_PIXELASYNC_LITE_C, "div_sclk_pixelasync_lite_c", + "mout_sclk_pixelasync_lite_c_b", DIV_CAM03, 8, 3), + DIV(CLK_DIV_PCLK_PIXELASYNC_LITE_C, "div_pclk_pixelasync_lite_c", + "div_sclk_pixelasync_lite_c_init", DIV_CAM03, 4, 2), + DIV(CLK_DIV_SCLK_PIXELASYNC_LITE_C_INIT, + "div_sclk_pixelasync_lite_c_init", + "mout_sclk_pixelasync_lite_c_init_b", DIV_CAM03, 0, 3), +}; + +static struct samsung_gate_clock cam0_gate_clks[] __initdata = { + /* ENABLE_ACLK_CAM00 */ + GATE(CLK_ACLK_CSIS1, "aclk_csis1", "div_aclk_csis1", ENABLE_ACLK_CAM00, + 6, 0, 0), + GATE(CLK_ACLK_CSIS0, "aclk_csis0", "div_aclk_csis0", ENABLE_ACLK_CAM00, + 5, 0, 0), + GATE(CLK_ACLK_3AA1, "aclk_3aa1", "div_aclk_3aa1", ENABLE_ACLK_CAM00, + 4, 0, 0), + GATE(CLK_ACLK_3AA0, "aclk_3aa0", "div_aclk_3aa0", ENABLE_ACLK_CAM00, + 3, 0, 0), + GATE(CLK_ACLK_LITE_D, "aclk_lite_d", "div_aclk_lite_d", + ENABLE_ACLK_CAM00, 2, 0, 0), + GATE(CLK_ACLK_LITE_B, "aclk_lite_b", "div_aclk_lite_b", + ENABLE_ACLK_CAM00, 1, 0, 0), + GATE(CLK_ACLK_LITE_A, "aclk_lite_a", "div_aclk_lite_a", + ENABLE_ACLK_CAM00, 0, 0, 0), + + /* ENABLE_ACLK_CAM01 */ + GATE(CLK_ACLK_AHBSYNCDN, "aclk_ahbsyncdn", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 31, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_D, "aclk_axius_lite_d", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 30, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_B, "aclk_axius_lite_b", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_A, "aclk_axius_lite_a", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_3AA1, "aclk_asyncapbm_3aa1", "div_pclk_3aa1", + ENABLE_ACLK_CAM01, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_3AA1, "aclk_asyncapbs_3aa1", "div_aclk_3aa1", + ENABLE_ACLK_CAM01, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_3AA0, "aclk_asyncapbm_3aa0", "div_pclk_3aa0", + ENABLE_ACLK_CAM01, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_3AA0, "aclk_asyncapbs_3aa0", "div_aclk_3aa0", + ENABLE_ACLK_CAM01, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_D, "aclk_asyncapbm_lite_d", + "div_pclk_lite_d", ENABLE_ACLK_CAM01, + 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_D, "aclk_asyncapbs_lite_d", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_B, "aclk_asyncapbm_lite_b", + "div_pclk_lite_b", ENABLE_ACLK_CAM01, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_B, "aclk_asyncapbs_lite_b", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_A, "aclk_asyncapbm_lite_a", + "div_pclk_lite_a", ENABLE_ACLK_CAM01, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_A, "aclk_asyncapbs_lite_a", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP0P, "aclk_asyncaxim_isp0p", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_3AA1, "aclk_asyncaxim_3aa1", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_3AA1, "aclk_asyncaxis_3aa1", + "div_aclk_3aa1", ENABLE_ACLK_CAM01, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_3AA0, "aclk_asyncaxim_3aa0", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_3AA0, "aclk_asyncaxis_3aa0", + "div_aclk_3aa0", ENABLE_ACLK_CAM01, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_D, "aclk_asyncaxim_lite_d", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_D, "aclk_asyncaxis_lite_d", + "div_aclk_lite_d", ENABLE_ACLK_CAM01, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_B, "aclk_asyncaxim_lite_b", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_B, "aclk_asyncaxis_lite_b", + "div_aclk_lite_b", ENABLE_ACLK_CAM01, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_A, "aclk_asyncaxim_lite_a", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_A, "aclk_asyncaxis_lite_a", + "div_aclk_lite_a", ENABLE_ACLK_CAM01, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISPSFRP, "aclk_ahb2apb_ispsfrp", + "div_pclk_cam0_50", ENABLE_ACLK_CAM01, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP0P, "aclk_axi2apb_isp0p", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2AHB_ISP0P, "aclk_axi2ahb_isp0p", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_IS0X, "aclk_xiu_is0x", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISP0EX, "aclk_xiu_isp0ex", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0NP_276, "aclk_cam0np_276", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0ND_400, "aclk_cam0nd_400", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_CAM02 */ + GATE(CLK_ACLK_SMMU_3AA1, "aclk_smmu_3aa1", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_3AA0, "aclk_smmu_3aa0", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_D, "aclk_smmu_lite_d", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_B, "aclk_smmu_lite_b", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_A, "aclk_smmu_lite_a", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_3AA1, "aclk_bts_3aa1", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_3AA0, "aclk_bts_3aa0", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_D, "aclk_bts_lite_d", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_B, "aclk_bts_lite_b", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_A, "aclk_bts_lite_a", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_CAM0 */ + GATE(CLK_PCLK_SMMU_3AA1, "pclk_smmu_3aa1", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_3AA0, "pclk_smmu_3aa0", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_D, "pclk_smmu_lite_d", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_B, "pclk_smmu_lite_b", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_A, "pclk_smmu_lite_a", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_3AA1, "pclk_bts_3aa1", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_3AA0, "pclk_bts_3aa0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_D, "pclk_bts_lite_d", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_B, "pclk_bts_lite_b", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_A, "pclk_bts_lite_a", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_CAM1, "pclk_asyncaxi_cam1", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_3AA1, "pclk_asyncaxi_3aa1", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_3AA0, "pclk_asyncaxi_3aa0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_LITE_D, "pclk_asyncaxi_lite_d", + "div_pclk_cam0_50", ENABLE_PCLK_CAM0, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_LITE_B, "pclk_asyncaxi_lite_b", + "div_pclk_cam0_50", ENABLE_PCLK_CAM0, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_LITE_A, "pclk_asyncaxi_lite_a", + "div_pclk_cam0_50", ENABLE_PCLK_CAM0, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_CAM0, "pclk_pmu_cam0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_CAM0, "pclk_sysreg_cam0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CMU_CAM0_LOCAL, "pclk_cmu_cam0_local", + "div_aclk_cam0_200", ENABLE_PCLK_CAM0, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CSIS1, "pclk_csis1", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CSIS0, "pclk_csis0", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_3AA1, "pclk_3aa1", "div_pclk_3aa1", + ENABLE_PCLK_CAM0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_3AA0, "pclk_3aa0", "div_pclk_3aa0", + ENABLE_PCLK_CAM0, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_D, "pclk_lite_d", "div_pclk_lite_d", + ENABLE_PCLK_CAM0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_B, "pclk_lite_b", "div_pclk_lite_b", + ENABLE_PCLK_CAM0, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_A, "pclk_lite_a", "div_pclk_lite_a", + ENABLE_PCLK_CAM0, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_CAM0 */ + GATE(CLK_PHYCLK_RXBYTECLKHS0_S4, "phyclk_rxbyteclkhs0_s4", + "mout_phyclk_rxbyteclkhs0_s4_user", + ENABLE_SCLK_CAM0, 8, 0, 0), + GATE(CLK_PHYCLK_RXBYTECLKHS0_S2A, "phyclk_rxbyteclkhs0_s2a", + "mout_phyclk_rxbyteclkhs0_s2a_user", + ENABLE_SCLK_CAM0, 7, 0, 0), + GATE(CLK_SCLK_LITE_FREECNT, "sclk_lite_freecnt", + "mout_sclk_lite_freecnt_c", ENABLE_SCLK_CAM0, 6, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_3AA1, "sclk_pixelasycm_3aa1", + "div_aclk_3aa1", ENABLE_SCLK_CAM0, 5, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_3AA0, "sclk_pixelasycm_3aa0", + "div_aclk_3aa0", ENABLE_SCLK_CAM0, 4, 0, 0), + GATE(CLK_SCLK_PIXELASYNCS_3AA0, "sclk_pixelasycs_3aa0", + "div_aclk_3aa0", ENABLE_SCLK_CAM0, 3, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_LITE_C, "sclk_pixelasyncm_lite_c", + "div_sclk_pixelasync_lite_c", + ENABLE_SCLK_CAM0, 2, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_LITE_C_INIT, "sclk_pixelasyncm_lite_c_init", + "div_sclk_pixelasync_lite_c_init", + ENABLE_SCLK_CAM0, 1, 0, 0), + GATE(CLK_SCLK_PIXELASYNCS_LITE_C_INIT, "sclk_pixelasyncs_lite_c_init", + "div_sclk_pixelasync_lite_c", + ENABLE_SCLK_CAM0, 0, 0, 0), +}; + +static struct samsung_cmu_info cam0_cmu_info __initdata = { + .mux_clks = cam0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cam0_mux_clks), + .div_clks = cam0_div_clks, + .nr_div_clks = ARRAY_SIZE(cam0_div_clks), + .gate_clks = cam0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cam0_gate_clks), + .fixed_clks = cam0_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(cam0_fixed_clks), + .nr_clk_ids = CAM0_NR_CLK, + .clk_regs = cam0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cam0_clk_regs), +}; + +static void __init exynos5433_cmu_cam0_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &cam0_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0", + exynos5433_cmu_cam0_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index fbc81e3424a6..f99cde7a278d 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -118,6 +118,9 @@ #define CLK_DIV_ACLK_MSCL_400 145 #define CLK_DIV_ACLK_ISP_DIS_400 146 #define CLK_DIV_ACLK_ISP_400 147 +#define CLK_DIV_ACLK_CAM0_333 148 +#define CLK_DIV_ACLK_CAM0_400 149 +#define CLK_DIV_ACLK_CAM0_552 150 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -159,8 +162,11 @@ #define CLK_ACLK_HEVC_400 237 #define CLK_ACLK_ISP_DIS_400 238 #define CLK_ACLK_ISP_400 239 +#define CLK_ACLK_CAM0_333 240 +#define CLK_ACLK_CAM0_400 241 +#define CLK_ACLK_CAM0_552 242 -#define TOP_NR_CLK 240 +#define TOP_NR_CLK 243 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1113,4 +1119,142 @@ #define ISP_NR_CLK 78 +/* CMU_CAM0 */ +#define CLK_PHYCLK_RXBYTEECLKHS0_S4_PHY 1 +#define CLK_PHYCLK_RXBYTEECLKHS0_S2A_PHY 2 + +#define CLK_MOUT_ACLK_CAM0_333_USER 3 +#define CLK_MOUT_ACLK_CAM0_400_USER 4 +#define CLK_MOUT_ACLK_CAM0_552_USER 5 +#define CLK_MOUT_PHYCLK_RXBYTECLKHS0_S4_USER 6 +#define CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2A_USER 7 +#define CLK_MOUT_ACLK_LITE_D_B 8 +#define CLK_MOUT_ACLK_LITE_D_A 9 +#define CLK_MOUT_ACLK_LITE_B_B 10 +#define CLK_MOUT_ACLK_LITE_B_A 11 +#define CLK_MOUT_ACLK_LITE_A_B 12 +#define CLK_MOUT_ACLK_LITE_A_A 13 +#define CLK_MOUT_ACLK_CAM0_400 14 +#define CLK_MOUT_ACLK_CSIS1_B 15 +#define CLK_MOUT_ACLK_CSIS1_A 16 +#define CLK_MOUT_ACLK_CSIS0_B 17 +#define CLK_MOUT_ACLK_CSIS0_A 18 +#define CLK_MOUT_ACLK_3AA1_B 19 +#define CLK_MOUT_ACLK_3AA1_A 20 +#define CLK_MOUT_ACLK_3AA0_B 21 +#define CLK_MOUT_ACLK_3AA0_A 22 +#define CLK_MOUT_SCLK_LITE_FREECNT_C 23 +#define CLK_MOUT_SCLK_LITE_FREECNT_B 24 +#define CLK_MOUT_SCLK_LITE_FREECNT_A 25 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_B 26 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_A 27 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_B 28 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_A 29 + +#define CLK_DIV_PCLK_CAM0_50 30 +#define CLK_DIV_ACLK_CAM0_200 31 +#define CLK_DIV_ACLK_CAM0_BUS_400 32 +#define CLK_DIV_PCLK_LITE_D 33 +#define CLK_DIV_ACLK_LITE_D 34 +#define CLK_DIV_PCLK_LITE_B 35 +#define CLK_DIV_ACLK_LITE_B 36 +#define CLK_DIV_PCLK_LITE_A 37 +#define CLK_DIV_ACLK_LITE_A 38 +#define CLK_DIV_ACLK_CSIS1 39 +#define CLK_DIV_ACLK_CSIS0 40 +#define CLK_DIV_PCLK_3AA1 41 +#define CLK_DIV_ACLK_3AA1 42 +#define CLK_DIV_PCLK_3AA0 43 +#define CLK_DIV_ACLK_3AA0 44 +#define CLK_DIV_SCLK_PIXELASYNC_LITE_C 45 +#define CLK_DIV_PCLK_PIXELASYNC_LITE_C 46 +#define CLK_DIV_SCLK_PIXELASYNC_LITE_C_INIT 47 + +#define CLK_ACLK_CSIS1 50 +#define CLK_ACLK_CSIS0 51 +#define CLK_ACLK_3AA1 52 +#define CLK_ACLK_3AA0 53 +#define CLK_ACLK_LITE_D 54 +#define CLK_ACLK_LITE_B 55 +#define CLK_ACLK_LITE_A 56 +#define CLK_ACLK_AHBSYNCDN 57 +#define CLK_ACLK_AXIUS_LITE_D 58 +#define CLK_ACLK_AXIUS_LITE_B 59 +#define CLK_ACLK_AXIUS_LITE_A 60 +#define CLK_ACLK_ASYNCAPBM_3AA1 61 +#define CLK_ACLK_ASYNCAPBS_3AA1 62 +#define CLK_ACLK_ASYNCAPBM_3AA0 63 +#define CLK_ACLK_ASYNCAPBS_3AA0 64 +#define CLK_ACLK_ASYNCAPBM_LITE_D 65 +#define CLK_ACLK_ASYNCAPBS_LITE_D 66 +#define CLK_ACLK_ASYNCAPBM_LITE_B 67 +#define CLK_ACLK_ASYNCAPBS_LITE_B 68 +#define CLK_ACLK_ASYNCAPBM_LITE_A 69 +#define CLK_ACLK_ASYNCAPBS_LITE_A 70 +#define CLK_ACLK_ASYNCAXIM_ISP0P 71 +#define CLK_ACLK_ASYNCAXIM_3AA1 72 +#define CLK_ACLK_ASYNCAXIS_3AA1 73 +#define CLK_ACLK_ASYNCAXIM_3AA0 74 +#define CLK_ACLK_ASYNCAXIS_3AA0 75 +#define CLK_ACLK_ASYNCAXIM_LITE_D 76 +#define CLK_ACLK_ASYNCAXIS_LITE_D 77 +#define CLK_ACLK_ASYNCAXIM_LITE_B 78 +#define CLK_ACLK_ASYNCAXIS_LITE_B 79 +#define CLK_ACLK_ASYNCAXIM_LITE_A 80 +#define CLK_ACLK_ASYNCAXIS_LITE_A 81 +#define CLK_ACLK_AHB2APB_ISPSFRP 82 +#define CLK_ACLK_AXI2APB_ISP0P 83 +#define CLK_ACLK_AXI2AHB_ISP0P 84 +#define CLK_ACLK_XIU_IS0X 85 +#define CLK_ACLK_XIU_ISP0EX 86 +#define CLK_ACLK_CAM0NP_276 87 +#define CLK_ACLK_CAM0ND_400 88 +#define CLK_ACLK_SMMU_3AA1 89 +#define CLK_ACLK_SMMU_3AA0 90 +#define CLK_ACLK_SMMU_LITE_D 91 +#define CLK_ACLK_SMMU_LITE_B 92 +#define CLK_ACLK_SMMU_LITE_A 93 +#define CLK_ACLK_BTS_3AA1 94 +#define CLK_ACLK_BTS_3AA0 95 +#define CLK_ACLK_BTS_LITE_D 96 +#define CLK_ACLK_BTS_LITE_B 97 +#define CLK_ACLK_BTS_LITE_A 98 +#define CLK_PCLK_SMMU_3AA1 99 +#define CLK_PCLK_SMMU_3AA0 100 +#define CLK_PCLK_SMMU_LITE_D 101 +#define CLK_PCLK_SMMU_LITE_B 102 +#define CLK_PCLK_SMMU_LITE_A 103 +#define CLK_PCLK_BTS_3AA1 104 +#define CLK_PCLK_BTS_3AA0 105 +#define CLK_PCLK_BTS_LITE_D 106 +#define CLK_PCLK_BTS_LITE_B 107 +#define CLK_PCLK_BTS_LITE_A 108 +#define CLK_PCLK_ASYNCAXI_CAM1 109 +#define CLK_PCLK_ASYNCAXI_3AA1 110 +#define CLK_PCLK_ASYNCAXI_3AA0 111 +#define CLK_PCLK_ASYNCAXI_LITE_D 112 +#define CLK_PCLK_ASYNCAXI_LITE_B 113 +#define CLK_PCLK_ASYNCAXI_LITE_A 114 +#define CLK_PCLK_PMU_CAM0 115 +#define CLK_PCLK_SYSREG_CAM0 116 +#define CLK_PCLK_CMU_CAM0_LOCAL 117 +#define CLK_PCLK_CSIS1 118 +#define CLK_PCLK_CSIS0 119 +#define CLK_PCLK_3AA1 120 +#define CLK_PCLK_3AA0 121 +#define CLK_PCLK_LITE_D 122 +#define CLK_PCLK_LITE_B 123 +#define CLK_PCLK_LITE_A 124 +#define CLK_PHYCLK_RXBYTECLKHS0_S4 125 +#define CLK_PHYCLK_RXBYTECLKHS0_S2A 126 +#define CLK_SCLK_LITE_FREECNT 127 +#define CLK_SCLK_PIXELASYNCM_3AA1 128 +#define CLK_SCLK_PIXELASYNCM_3AA0 129 +#define CLK_SCLK_PIXELASYNCS_3AA0 130 +#define CLK_SCLK_PIXELASYNCM_LITE_C 131 +#define CLK_SCLK_PIXELASYNCM_LITE_C_INIT 132 +#define CLK_SCLK_PIXELASYNCS_LITE_C_INIT 133 + +#define CAM0_NR_CLK 134 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From a5958a939bbf93e6b77cb3626c6aebde237ad759 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:56 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_CAM1 domain This patch adds the mux/divider/gate clocks for CMU_CAM1 domain which generates the clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 32 ++ drivers/clk/samsung/clk-exynos5433.c | 435 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 147 ++++++- 3 files changed, 612 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 84002e4b52e5..63379b04e052 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -48,6 +48,8 @@ Required Properties: - "samsung,exynos5433-cmu-cam0" - clock controller compatible for CMU_CAM0 which generates clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1} IPs. + - "samsung,exynos5433-cmu-cam1" - clock controller compatible for CMU_CAM1 + which generates clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -153,6 +155,15 @@ Required Properties: - aclk_cam0_400 - aclk_cam0_552 + Input clocks for cam1 clock controller: + - oscclk + - sclk_isp_uart_cam1 + - sclk_isp_spi1_cam1 + - sclk_isp_spi0_cam1 + - aclk_cam1_333 + - aclk_cam1_400 + - aclk_cam1_552 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -414,6 +425,27 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_CAM0_552>; }; + cmu_cam1: clock-controller@145d0000 { + compatible = "samsung,exynos5433-cmu-cam1"; + reg = <0x145d0000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_isp_uart_cam1", + "sclk_isp_spi1_cam1", + "sclk_isp_spi0_cam1", + "aclk_cam1_333", + "aclk_cam1_400", + "aclk_cam1_552"; + clocks = <&xxti>, + <&cmu_top CLK_SCLK_ISP_UART_CAM1>, + <&cmu_top CLK_SCLK_ISP_SPI1_CAM1>, + <&cmu_top CLK_SCLK_ISP_SPI0_CAM1>, + <&cmu_top CLK_ACLK_CAM1_333>, + <&cmu_top CLK_ACLK_CAM1_400>, + <&cmu_top CLK_ACLK_CAM1_552>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index ce6487375670..1a005c1f7c4b 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -405,6 +405,12 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { static struct samsung_div_clock top_div_clks[] __initdata = { /* DIV_TOP0 */ + DIV(CLK_DIV_ACLK_CAM1_333, "div_aclk_cam1_333", "mout_aclk_cam1_333", + DIV_TOP0, 28, 3), + DIV(CLK_DIV_ACLK_CAM1_400, "div_aclk_cam1_400", "mout_bus_pll_user", + DIV_TOP0, 24, 3), + DIV(CLK_DIV_ACLK_CAM1_552, "div_aclk_cam1_552", "mout_aclk_cam1_552_b", + DIV_TOP0, 20, 3), DIV(CLK_DIV_ACLK_CAM0_333, "div_aclk_cam0_333", "mout_mfc_pll_user", DIV_TOP0, 16, 3), DIV(CLK_DIV_ACLK_CAM0_400, "div_aclk_cam0_400", "mout_bus_pll_user", @@ -464,6 +470,32 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_SCLK_JPEG, "div_sclk_jpeg", "mout_sclk_jpeg_c", DIV_TOP_MSCL, 0, 4), + /* DIV_TOP_CAM10 */ + DIV(CLK_DIV_SCLK_ISP_UART, "div_sclk_isp_uart", "mout_sclk_isp_uart", + DIV_TOP_CAM10, 24, 5), + DIV(CLK_DIV_SCLK_ISP_SPI1_B, "div_sclk_isp_spi1_b", + "div_sclk_isp_spi1_a", DIV_TOP_CAM10, 16, 8), + DIV(CLK_DIV_SCLK_ISP_SPI1_A, "div_sclk_isp_spi1_a", + "mout_sclk_isp_spi1", DIV_TOP_CAM10, 12, 4), + DIV(CLK_DIV_SCLK_ISP_SPI0_B, "div_sclk_isp_spi0_b", + "div_sclk_isp_spi0_a", DIV_TOP_CAM10, 4, 8), + DIV(CLK_DIV_SCLK_ISP_SPI0_A, "div_sclk_isp_spi0_a", + "mout_sclk_isp_spi0", DIV_TOP_CAM10, 0, 4), + + /* DIV_TOP_CAM11 */ + DIV(CLK_DIV_SCLK_ISP_SENSOR2_B, "div_sclk_isp_sensor2_b", + "div_sclk_isp_sensor2_a", DIV_TOP_CAM11, 20, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR2_A, "div_sclk_isp_sensor2_a", + "mout_sclk_isp_sensor2", DIV_TOP_CAM11, 16, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR1_B, "div_sclk_isp_sensor1_b", + "div_sclk_isp_sensor1_a", DIV_TOP_CAM11, 12, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR1_A, "div_sclk_isp_sensor1_a", + "mout_sclk_isp_sensor1", DIV_TOP_CAM11, 8, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR0_B, "div_sclk_isp_sensor0_b", + "div_sclk_isp_sensor0_a", DIV_TOP_CAM11, 12, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR0_A, "div_sclk_isp_sensor0_a", + "mout_sclk_isp_sensor0", DIV_TOP_CAM11, 8, 4), + /* DIV_TOP_FSYS0 */ DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", DIV_TOP_FSYS0, 16, 8), @@ -572,6 +604,15 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1_333, "aclk_cam1_333", "div_aclk_cam1_333", + ENABLE_ACLK_TOP, 13, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1_400, "aclk_cam1_400", "div_aclk_cam1_400", + ENABLE_ACLK_TOP, 12, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1_552, "aclk_cam1_552", "div_aclk_cam1_552", + ENABLE_ACLK_TOP, 11, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_CAM0_333, "aclk_cam0_333", "div_aclk_cam0_333", ENABLE_ACLK_TOP, 10, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -604,6 +645,22 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_SCLK_JPEG_MSCL, "sclk_jpeg_mscl", "div_sclk_jpeg", ENABLE_SCLK_TOP_MSCL, 0, 0, 0), + /* ENABLE_SCLK_TOP_CAM1 */ + GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "div_sclk_isp_sensor2_b", + ENABLE_SCLK_TOP_CAM1, 7, 0, 0), + GATE(CLK_SCLK_ISP_SENSOR1, "sclk_isp_sensor1", "div_sclk_isp_sensor1_b", + ENABLE_SCLK_TOP_CAM1, 6, 0, 0), + GATE(CLK_SCLK_ISP_SENSOR0, "sclk_isp_sensor0", "div_sclk_isp_sensor0_b", + ENABLE_SCLK_TOP_CAM1, 5, 0, 0), + GATE(CLK_SCLK_ISP_MCTADC_CAM1, "sclk_isp_mctadc_cam1", "oscclk", + ENABLE_SCLK_TOP_CAM1, 4, 0, 0), + GATE(CLK_SCLK_ISP_UART_CAM1, "sclk_isp_uart_cam1", "div_sclk_isp_uart", + ENABLE_SCLK_TOP_CAM1, 2, 0, 0), + GATE(CLK_SCLK_ISP_SPI1_CAM1, "sclk_isp_spi1_cam1", "div_sclk_isp_spi1_b", + ENABLE_SCLK_TOP_CAM1, 1, 0, 0), + GATE(CLK_SCLK_ISP_SPI0_CAM1, "sclk_isp_spi0_cam1", "div_sclk_isp_spi0_b", + ENABLE_SCLK_TOP_CAM1, 0, 0, 0), + /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", ENABLE_SCLK_TOP_FSYS, 7, 0, 0), @@ -4986,3 +5043,381 @@ static void __init exynos5433_cmu_cam0_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0", exynos5433_cmu_cam0_init); + +/* + * Register offset definitions for CMU_CAM1 + */ +#define MUX_SEL_CAM10 0x0200 +#define MUX_SEL_CAM11 0x0204 +#define MUX_SEL_CAM12 0x0208 +#define MUX_ENABLE_CAM10 0x0300 +#define MUX_ENABLE_CAM11 0x0304 +#define MUX_ENABLE_CAM12 0x0308 +#define MUX_STAT_CAM10 0x0400 +#define MUX_STAT_CAM11 0x0404 +#define MUX_STAT_CAM12 0x0408 +#define MUX_IGNORE_CAM11 0x0504 +#define DIV_CAM10 0x0600 +#define DIV_CAM11 0x0604 +#define DIV_STAT_CAM10 0x0700 +#define DIV_STAT_CAM11 0x0704 +#define ENABLE_ACLK_CAM10 0X0800 +#define ENABLE_ACLK_CAM11 0X0804 +#define ENABLE_ACLK_CAM12 0X0808 +#define ENABLE_PCLK_CAM1 0X0900 +#define ENABLE_SCLK_CAM1 0X0a00 +#define ENABLE_IP_CAM10 0X0b00 +#define ENABLE_IP_CAM11 0X0b04 +#define ENABLE_IP_CAM12 0X0b08 + +static unsigned long cam1_clk_regs[] __initdata = { + MUX_SEL_CAM10, + MUX_SEL_CAM11, + MUX_SEL_CAM12, + MUX_ENABLE_CAM10, + MUX_ENABLE_CAM11, + MUX_ENABLE_CAM12, + MUX_STAT_CAM10, + MUX_STAT_CAM11, + MUX_STAT_CAM12, + MUX_IGNORE_CAM11, + DIV_CAM10, + DIV_CAM11, + DIV_STAT_CAM10, + DIV_STAT_CAM11, + ENABLE_ACLK_CAM10, + ENABLE_ACLK_CAM11, + ENABLE_ACLK_CAM12, + ENABLE_PCLK_CAM1, + ENABLE_SCLK_CAM1, + ENABLE_IP_CAM10, + ENABLE_IP_CAM11, + ENABLE_IP_CAM12, +}; + +PNAME(mout_sclk_isp_uart_user_p) = { "oscclk", "sclk_isp_uart_cam1", }; +PNAME(mout_sclk_isp_spi1_user_p) = { "oscclk", "sclk_isp_spi1_cam1", }; +PNAME(mout_sclk_isp_spi0_user_p) = { "oscclk", "sclk_isp_spi0_cam1", }; + +PNAME(mout_aclk_cam1_333_user_p) = { "oscclk", "aclk_cam1_333", }; +PNAME(mout_aclk_cam1_400_user_p) = { "oscclk", "aclk_cam1_400", }; +PNAME(mout_aclk_cam1_552_user_p) = { "oscclk", "aclk_cam1_552", }; + +PNAME(mout_phyclk_rxbyteclkhs0_s2b_user_p) = { "oscclk", + "phyclk_rxbyteclkhs0_s2b_phy", }; + +PNAME(mout_aclk_csis2_b_p) = { "mout_aclk_csis2_a", + "mout_aclk_cam1_333_user", }; +PNAME(mout_aclk_csis2_a_p) = { "mout_aclk_cam1_552_user", + "mout_aclk_cam1_400_user", }; + +PNAME(mout_aclk_fd_b_p) = { "mout_aclk_fd_a", + "mout_aclk_cam1_333_user", }; +PNAME(mout_aclk_fd_a_p) = { "mout_aclk_cam1_552_user", + "mout_aclk_cam1_400_user", }; + +PNAME(mout_aclk_lite_c_b_p) = { "mout_aclk_lite_c_a", + "mout_aclk_cam1_333_user", }; +PNAME(mout_aclk_lite_c_a_p) = { "mout_aclk_cam1_552_user", + "mout_aclk_cam1_400_user", }; + +static struct samsung_fixed_rate_clock cam1_fixed_clks[] __initdata = { + FRATE(CLK_PHYCLK_RXBYTEECLKHS0_S2B, "phyclk_rxbyteclkhs0_s2b_phy", NULL, + CLK_IS_ROOT, 100000000), +}; + +static struct samsung_mux_clock cam1_mux_clks[] __initdata = { + /* MUX_SEL_CAM10 */ + MUX(CLK_MOUT_SCLK_ISP_UART_USER, "mout_sclk_isp_uart_user", + mout_sclk_isp_uart_user_p, MUX_SEL_CAM10, 20, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI1_USER, "mout_sclk_isp_spi1_user", + mout_sclk_isp_spi1_user_p, MUX_SEL_CAM10, 16, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI0_USER, "mout_sclk_isp_spi0_user", + mout_sclk_isp_spi0_user_p, MUX_SEL_CAM10, 12, 1), + MUX(CLK_MOUT_ACLK_CAM1_333_USER, "mout_aclk_cam1_333_user", + mout_aclk_cam1_333_user_p, MUX_SEL_CAM10, 8, 1), + MUX(CLK_MOUT_ACLK_CAM1_400_USER, "mout_aclk_cam1_400_user", + mout_aclk_cam1_400_user_p, MUX_SEL_CAM01, 4, 1), + MUX(CLK_MOUT_ACLK_CAM1_552_USER, "mout_aclk_cam1_552_user", + mout_aclk_cam1_552_user_p, MUX_SEL_CAM01, 0, 1), + + /* MUX_SEL_CAM11 */ + MUX(CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2B_USER, + "mout_phyclk_rxbyteclkhs0_s2b_user", + mout_phyclk_rxbyteclkhs0_s2b_user_p, + MUX_SEL_CAM11, 0, 1), + + /* MUX_SEL_CAM12 */ + MUX(CLK_MOUT_ACLK_CSIS2_B, "mout_aclk_csis2_b", mout_aclk_csis2_b_p, + MUX_SEL_CAM12, 20, 1), + MUX(CLK_MOUT_ACLK_CSIS2_A, "mout_aclk_csis2_a", mout_aclk_csis2_a_p, + MUX_SEL_CAM12, 16, 1), + MUX(CLK_MOUT_ACLK_FD_B, "mout_aclk_fd_b", mout_aclk_fd_b_p, + MUX_SEL_CAM12, 12, 1), + MUX(CLK_MOUT_ACLK_FD_A, "mout_aclk_fd_a", mout_aclk_fd_a_p, + MUX_SEL_CAM12, 8, 1), + MUX(CLK_MOUT_ACLK_LITE_C_B, "mout_aclk_lite_c_b", mout_aclk_lite_c_b_p, + MUX_SEL_CAM12, 4, 1), + MUX(CLK_MOUT_ACLK_LITE_C_A, "mout_aclk_lite_c_a", mout_aclk_lite_c_a_p, + MUX_SEL_CAM12, 0, 1), +}; + +static struct samsung_div_clock cam1_div_clks[] __initdata = { + /* DIV_CAM10 */ + DIV(CLK_DIV_SCLK_ISP_WPWM, "div_sclk_isp_wpwm", + "div_pclk_cam1_83", DIV_CAM10, 16, 2), + DIV(CLK_DIV_PCLK_CAM1_83, "div_pclk_cam1_83", + "mout_aclk_cam1_333_user", DIV_CAM10, 12, 2), + DIV(CLK_DIV_PCLK_CAM1_166, "div_pclk_cam1_166", + "mout_aclk_cam1_333_user", DIV_CAM10, 8, 2), + DIV(CLK_DIV_PCLK_DBG_CAM1, "div_pclk_dbg_cam1", + "mout_aclk_cam1_552_user", DIV_CAM10, 4, 3), + DIV(CLK_DIV_ATCLK_CAM1, "div_atclk_cam1", "mout_aclk_cam1_552_user", + DIV_CAM10, 0, 3), + + /* DIV_CAM11 */ + DIV(CLK_DIV_ACLK_CSIS2, "div_aclk_csis2", "mout_aclk_csis2_b", + DIV_CAM11, 16, 3), + DIV(CLK_DIV_PCLK_FD, "div_pclk_fd", "div_aclk_fd", DIV_CAM11, 12, 2), + DIV(CLK_DIV_ACLK_FD, "div_aclk_fd", "mout_aclk_fd_b", DIV_CAM11, 8, 3), + DIV(CLK_DIV_PCLK_LITE_C, "div_pclk_lite_c", "div_aclk_lite_c", + DIV_CAM11, 4, 2), + DIV(CLK_DIV_ACLK_LITE_C, "div_aclk_lite_c", "mout_aclk_lite_c_b", + DIV_CAM11, 0, 3), +}; + +static struct samsung_gate_clock cam1_gate_clks[] __initdata = { + /* ENABLE_ACLK_CAM10 */ + GATE(CLK_ACLK_ISP_GIC, "aclk_isp_gic", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM10, 4, 0, 0), + GATE(CLK_ACLK_FD, "aclk_fd", "div_aclk_fd", + ENABLE_ACLK_CAM10, 3, 0, 0), + GATE(CLK_ACLK_LITE_C, "aclk_lite_c", "div_aclk_lite_c", + ENABLE_ACLK_CAM10, 1, 0, 0), + GATE(CLK_ACLK_CSIS2, "aclk_csis2", "div_aclk_csis2", + ENABLE_ACLK_CAM10, 0, 0, 0), + + /* ENABLE_ACLK_CAM11 */ + GATE(CLK_ACLK_ASYNCAPBM_FD, "aclk_asyncapbm_fd", "div_pclk_fd", + ENABLE_ACLK_CAM11, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_FD, "aclk_asyncapbs_fd", "div_pclk_cam1_166", + ENABLE_ACLK_CAM11, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_C, "aclk_asyncapbm_lite_c", + "div_pclk_lite_c", ENABLE_ACLK_CAM11, + 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_C, "aclk_asyncapbs_lite_c", + "div_pclk_cam1_166", ENABLE_ACLK_CAM11, + 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBS_SFRISP2H2, "aclk_asyncahbs_sfrisp2h2", + "div_pclk_cam1_83", ENABLE_ACLK_CAM11, + 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBS_SFRISP2H1, "aclk_asyncahbs_sfrisp2h1", + "div_pclk_cam1_83", ENABLE_ACLK_CAM11, + 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_CA5, "aclk_asyncaxim_ca5", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CA5, "aclk_asyncaxis_ca5", + "mout_aclk_cam1_552_user", ENABLE_ACLK_CAM11, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISPX2, "aclk_asyncaxis_ispx2", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISPX1, "aclk_asyncaxis_ispx1", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISPX0, "aclk_asyncaxis_ispx0", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISPEX, "aclk_asyncaxim_ispex", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP3P, "aclk_asyncaxim_isp3p", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISP3P, "aclk_asyncaxis_isp3p", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_FD, "aclk_asyncaxim_fd", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_FD, "aclk_asyncaxis_fd", "div_aclk_fd", + ENABLE_ACLK_CAM11, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_C, "aclk_asyncaxim_lite_c", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_C, "aclk_asyncaxis_lite_c", + "div_aclk_lite_c", ENABLE_ACLK_CAM11, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP5P, "aclk_ahb2apb_isp5p", "div_pclk_cam1_83", + ENABLE_ACLK_CAM11, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP3P, "aclk_ahb2apb_isp3p", "div_pclk_cam1_83", + ENABLE_ACLK_CAM11, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP3P, "aclk_axi2apb_isp3p", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_SFRISP2H, "aclk_ahb_sfrisp2h", "div_pclk_cam1_83", + ENABLE_ACLK_CAM11, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_HX_R, "aclk_axi_isp_hx_r", "div_pclk_cam1_166", + ENABLE_ACLK_CAM11, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_CX_R, "aclk_axi_isp_cx_r", "div_pclk_cam1_166", + ENABLE_ACLK_CAM11, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_HX, "aclk_axi_isp_hx", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_CX, "aclk_axi_isp_cx", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPX, "aclk_xiu_ispx", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPEX, "aclk_xiu_ispex", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM11, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1NP_333, "aclk_cam1np_333", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1ND_400, "aclk_cam1nd_400", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM11, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_CAM12 */ + GATE(CLK_ACLK_SMMU_ISPCPU, "aclk_smmu_ispcpu", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_FD, "aclk_smmu_fd", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_C, "aclk_smmu_lite_c", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_ISP3P, "aclk_bts_isp3p", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_FD, "aclk_bts_fd", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_C, "aclk_bts_lite_c", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHBDN_SFRISP2H, "aclk_ahbdn_sfrisp2h", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM12, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHBDN_ISP5P, "aclk_aclk-shbdn_isp5p", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM12, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_ISP3P, "aclk_axius_isp3p", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_FD, "aclk_axius_fd", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_C, "aclk_axius_lite_c", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_CAM1 */ + GATE(CLK_PCLK_SMMU_ISPCPU, "pclk_smmu_ispcpu", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_FD, "pclk_smmu_fd", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_C, "pclk_smmu_lite_c", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_ISP3P, "pclk_bts_isp3p", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_FD, "pclk_bts_fd", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_C, "pclk_bts_lite_c", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_CA5, "pclk_asyncaxim_ca5", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_ISPEX, "pclk_asyncaxim_ispex", + "div_pclk_cam1_83", ENABLE_PCLK_CAM1, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_ISP3P, "pclk_asyncaxim_isp3p", + "div_pclk_cam1_83", ENABLE_PCLK_CAM1, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_FD, "pclk_asyncaxim_fd", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_LITE_C, "pclk_asyncaxim_lite_c", + "div_pclk_cam1_83", ENABLE_PCLK_CAM1, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_CAM1, "pclk_pmu_cam1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_CAM1, "pclk_sysreg_cam1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CMU_CAM1_LOCAL, "pclk_cmu_cam1_local", + "div_pclk_cam1_166", ENABLE_PCLK_CAM1, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_MCTADC, "pclk_isp_mctadc", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_WDT, "pclk_isp_wdt", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_PWM, "pclk_isp_pwm", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_UART, "pclk_isp_uart", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_MCUCTL, "pclk_isp_mcuctl", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_SPI1, "pclk_isp_spi1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_SPI0, "pclk_isp_spi0", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_I2C2, "pclk_isp_i2c2", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_I2C1, "pclk_isp_i2c1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_I2C0, "pclk_isp_i2c0", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_MPWM, "pclk_isp_wpwm", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_FD, "pclk_fd", "div_pclk_fd", + ENABLE_PCLK_CAM1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_C, "pclk_lite_c", "div_pclk_lite_c", + ENABLE_PCLK_CAM1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CSIS2, "pclk_csis2", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_CAM1 */ + GATE(CLK_SCLK_ISP_I2C2, "sclk_isp_i2c2", "oscclk", ENABLE_SCLK_CAM1, + 15, 0, 0), + GATE(CLK_SCLK_ISP_I2C1, "sclk_isp_i2c1", "oscclk", ENABLE_SCLK_CAM1, + 14, 0, 0), + GATE(CLK_SCLK_ISP_I2C0, "sclk_isp_i2c0", "oscclk", ENABLE_SCLK_CAM1, + 13, 0, 0), + GATE(CLK_SCLK_ISP_PWM, "sclk_isp_pwm", "oscclk", ENABLE_SCLK_CAM1, + 12, 0, 0), + GATE(CLK_PHYCLK_RXBYTECLKHS0_S2B, "phyclk_rxbyteclkhs0_s2b", + "mout_phyclk_rxbyteclkhs0_s2b_user", + ENABLE_SCLK_CAM1, 11, 0, 0), + GATE(CLK_SCLK_LITE_C_FREECNT, "sclk_lite_c_freecnt", "div_pclk_lite_c", + ENABLE_SCLK_CAM1, 10, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_FD, "sclk_pixelasyncm_fd", "div_aclk_fd", + ENABLE_SCLK_CAM1, 9, 0, 0), + GATE(CLK_SCLK_ISP_MCTADC, "sclk_isp_mctadc", "sclk_isp_mctadc_cam1", + ENABLE_SCLK_CAM1, 7, 0, 0), + GATE(CLK_SCLK_ISP_UART, "sclk_isp_uart", "mout_sclk_isp_uart_user", + ENABLE_SCLK_CAM1, 6, 0, 0), + GATE(CLK_SCLK_ISP_SPI1, "sclk_isp_spi1", "mout_sclk_isp_spi1_user", + ENABLE_SCLK_CAM1, 5, 0, 0), + GATE(CLK_SCLK_ISP_SPI0, "sclk_isp_spi0", "mout_sclk_isp_spi0_user", + ENABLE_SCLK_CAM1, 4, 0, 0), + GATE(CLK_SCLK_ISP_MPWM, "sclk_isp_wpwm", "div_sclk_isp_wpwm", + ENABLE_SCLK_CAM1, 3, 0, 0), + GATE(CLK_PCLK_DBG_ISP, "sclk_dbg_isp", "div_pclk_dbg_cam1", + ENABLE_SCLK_CAM1, 2, 0, 0), + GATE(CLK_ATCLK_ISP, "atclk_isp", "div_atclk_cam1", + ENABLE_SCLK_CAM1, 1, 0, 0), + GATE(CLK_SCLK_ISP_CA5, "sclk_isp_ca5", "mout_aclk_cam1_552_user", + ENABLE_SCLK_CAM1, 0, 0, 0), +}; + +static struct samsung_cmu_info cam1_cmu_info __initdata = { + .mux_clks = cam1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cam1_mux_clks), + .div_clks = cam1_div_clks, + .nr_div_clks = ARRAY_SIZE(cam1_div_clks), + .gate_clks = cam1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cam1_gate_clks), + .fixed_clks = cam1_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(cam1_fixed_clks), + .nr_clk_ids = CAM1_NR_CLK, + .clk_regs = cam1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cam1_clk_regs), +}; + +static void __init exynos5433_cmu_cam1_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &cam1_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1", + exynos5433_cmu_cam1_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index f99cde7a278d..4853bc598b57 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -121,6 +121,20 @@ #define CLK_DIV_ACLK_CAM0_333 148 #define CLK_DIV_ACLK_CAM0_400 149 #define CLK_DIV_ACLK_CAM0_552 150 +#define CLK_DIV_ACLK_CAM1_333 151 +#define CLK_DIV_ACLK_CAM1_400 152 +#define CLK_DIV_ACLK_CAM1_552 153 +#define CLK_DIV_SCLK_ISP_UART 154 +#define CLK_DIV_SCLK_ISP_SPI1_B 155 +#define CLK_DIV_SCLK_ISP_SPI1_A 156 +#define CLK_DIV_SCLK_ISP_SPI0_B 157 +#define CLK_DIV_SCLK_ISP_SPI0_A 158 +#define CLK_DIV_SCLK_ISP_SENSOR2_B 159 +#define CLK_DIV_SCLK_ISP_SENSOR2_A 160 +#define CLK_DIV_SCLK_ISP_SENSOR1_B 161 +#define CLK_DIV_SCLK_ISP_SENSOR1_A 162 +#define CLK_DIV_SCLK_ISP_SENSOR0_B 163 +#define CLK_DIV_SCLK_ISP_SENSOR0_A 164 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -165,8 +179,18 @@ #define CLK_ACLK_CAM0_333 240 #define CLK_ACLK_CAM0_400 241 #define CLK_ACLK_CAM0_552 242 - -#define TOP_NR_CLK 243 +#define CLK_ACLK_CAM1_333 243 +#define CLK_ACLK_CAM1_400 244 +#define CLK_ACLK_CAM1_552 245 +#define CLK_SCLK_ISP_SENSOR2 246 +#define CLK_SCLK_ISP_SENSOR1 247 +#define CLK_SCLK_ISP_SENSOR0 248 +#define CLK_SCLK_ISP_MCTADC_CAM1 249 +#define CLK_SCLK_ISP_UART_CAM1 250 +#define CLK_SCLK_ISP_SPI1_CAM1 251 +#define CLK_SCLK_ISP_SPI0_CAM1 252 + +#define TOP_NR_CLK 253 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1257,4 +1281,123 @@ #define CAM0_NR_CLK 134 +/* CMU_CAM1 */ +#define CLK_PHYCLK_RXBYTEECLKHS0_S2B 1 + +#define CLK_MOUT_SCLK_ISP_UART_USER 2 +#define CLK_MOUT_SCLK_ISP_SPI1_USER 3 +#define CLK_MOUT_SCLK_ISP_SPI0_USER 4 +#define CLK_MOUT_ACLK_CAM1_333_USER 5 +#define CLK_MOUT_ACLK_CAM1_400_USER 6 +#define CLK_MOUT_ACLK_CAM1_552_USER 7 +#define CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2B_USER 8 +#define CLK_MOUT_ACLK_CSIS2_B 9 +#define CLK_MOUT_ACLK_CSIS2_A 10 +#define CLK_MOUT_ACLK_FD_B 11 +#define CLK_MOUT_ACLK_FD_A 12 +#define CLK_MOUT_ACLK_LITE_C_B 13 +#define CLK_MOUT_ACLK_LITE_C_A 14 + +#define CLK_DIV_SCLK_ISP_WPWM 15 +#define CLK_DIV_PCLK_CAM1_83 16 +#define CLK_DIV_PCLK_CAM1_166 17 +#define CLK_DIV_PCLK_DBG_CAM1 18 +#define CLK_DIV_ATCLK_CAM1 19 +#define CLK_DIV_ACLK_CSIS2 20 +#define CLK_DIV_PCLK_FD 21 +#define CLK_DIV_ACLK_FD 22 +#define CLK_DIV_PCLK_LITE_C 23 +#define CLK_DIV_ACLK_LITE_C 24 + +#define CLK_ACLK_ISP_GIC 25 +#define CLK_ACLK_FD 26 +#define CLK_ACLK_LITE_C 27 +#define CLK_ACLK_CSIS2 28 +#define CLK_ACLK_ASYNCAPBM_FD 29 +#define CLK_ACLK_ASYNCAPBS_FD 30 +#define CLK_ACLK_ASYNCAPBM_LITE_C 31 +#define CLK_ACLK_ASYNCAPBS_LITE_C 32 +#define CLK_ACLK_ASYNCAHBS_SFRISP2H2 33 +#define CLK_ACLK_ASYNCAHBS_SFRISP2H1 34 +#define CLK_ACLK_ASYNCAXIM_CA5 35 +#define CLK_ACLK_ASYNCAXIS_CA5 36 +#define CLK_ACLK_ASYNCAXIS_ISPX2 37 +#define CLK_ACLK_ASYNCAXIS_ISPX1 38 +#define CLK_ACLK_ASYNCAXIS_ISPX0 39 +#define CLK_ACLK_ASYNCAXIM_ISPEX 40 +#define CLK_ACLK_ASYNCAXIM_ISP3P 41 +#define CLK_ACLK_ASYNCAXIS_ISP3P 42 +#define CLK_ACLK_ASYNCAXIM_FD 43 +#define CLK_ACLK_ASYNCAXIS_FD 44 +#define CLK_ACLK_ASYNCAXIM_LITE_C 45 +#define CLK_ACLK_ASYNCAXIS_LITE_C 46 +#define CLK_ACLK_AHB2APB_ISP5P 47 +#define CLK_ACLK_AHB2APB_ISP3P 48 +#define CLK_ACLK_AXI2APB_ISP3P 49 +#define CLK_ACLK_AHB_SFRISP2H 50 +#define CLK_ACLK_AXI_ISP_HX_R 51 +#define CLK_ACLK_AXI_ISP_CX_R 52 +#define CLK_ACLK_AXI_ISP_HX 53 +#define CLK_ACLK_AXI_ISP_CX 54 +#define CLK_ACLK_XIU_ISPX 55 +#define CLK_ACLK_XIU_ISPEX 56 +#define CLK_ACLK_CAM1NP_333 57 +#define CLK_ACLK_CAM1ND_400 58 +#define CLK_ACLK_SMMU_ISPCPU 59 +#define CLK_ACLK_SMMU_FD 60 +#define CLK_ACLK_SMMU_LITE_C 61 +#define CLK_ACLK_BTS_ISP3P 62 +#define CLK_ACLK_BTS_FD 63 +#define CLK_ACLK_BTS_LITE_C 64 +#define CLK_ACLK_AHBDN_SFRISP2H 65 +#define CLK_ACLK_AHBDN_ISP5P 66 +#define CLK_ACLK_AXIUS_ISP3P 67 +#define CLK_ACLK_AXIUS_FD 68 +#define CLK_ACLK_AXIUS_LITE_C 69 +#define CLK_PCLK_SMMU_ISPCPU 70 +#define CLK_PCLK_SMMU_FD 71 +#define CLK_PCLK_SMMU_LITE_C 72 +#define CLK_PCLK_BTS_ISP3P 73 +#define CLK_PCLK_BTS_FD 74 +#define CLK_PCLK_BTS_LITE_C 75 +#define CLK_PCLK_ASYNCAXIM_CA5 76 +#define CLK_PCLK_ASYNCAXIM_ISPEX 77 +#define CLK_PCLK_ASYNCAXIM_ISP3P 78 +#define CLK_PCLK_ASYNCAXIM_FD 79 +#define CLK_PCLK_ASYNCAXIM_LITE_C 80 +#define CLK_PCLK_PMU_CAM1 81 +#define CLK_PCLK_SYSREG_CAM1 82 +#define CLK_PCLK_CMU_CAM1_LOCAL 83 +#define CLK_PCLK_ISP_MCTADC 84 +#define CLK_PCLK_ISP_WDT 85 +#define CLK_PCLK_ISP_PWM 86 +#define CLK_PCLK_ISP_UART 87 +#define CLK_PCLK_ISP_MCUCTL 88 +#define CLK_PCLK_ISP_SPI1 89 +#define CLK_PCLK_ISP_SPI0 90 +#define CLK_PCLK_ISP_I2C2 91 +#define CLK_PCLK_ISP_I2C1 92 +#define CLK_PCLK_ISP_I2C0 93 +#define CLK_PCLK_ISP_MPWM 94 +#define CLK_PCLK_FD 95 +#define CLK_PCLK_LITE_C 96 +#define CLK_PCLK_CSIS2 97 +#define CLK_SCLK_ISP_I2C2 98 +#define CLK_SCLK_ISP_I2C1 99 +#define CLK_SCLK_ISP_I2C0 100 +#define CLK_SCLK_ISP_PWM 101 +#define CLK_PHYCLK_RXBYTECLKHS0_S2B 102 +#define CLK_SCLK_LITE_C_FREECNT 103 +#define CLK_SCLK_PIXELASYNCM_FD 104 +#define CLK_SCLK_ISP_MCTADC 105 +#define CLK_SCLK_ISP_UART 106 +#define CLK_SCLK_ISP_SPI1 107 +#define CLK_SCLK_ISP_SPI0 108 +#define CLK_SCLK_ISP_MPWM 109 +#define CLK_PCLK_DBG_ISP 110 +#define CLK_ATCLK_ISP 111 +#define CLK_SCLK_ISP_CA5 112 + +#define CAM1_NR_CLK 113 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From b2f0e5f28e0686c0d5db238357a2e32555e97633 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 4 Feb 2015 10:12:59 +0900 Subject: clk: samsung: exynos5433: Move CLK_SCLK_HDMI_SPDIF_DISP clock to CMU_TOP domain This patch fixes the bug of CLK_SCLK_HDMI_SPDIF_DISP clock because this clock should be included in CMU_TOP domain. So, this patch moves the CLK_SCLK_HDMI_ SPDIF_DISP clock from CMU_MIF to CMU_TOP domain. Reported-by: Sylwester Nawrocki Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 10 +++++----- include/dt-bindings/clock/exynos5433.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 1a005c1f7c4b..387e3e39e635 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -661,6 +661,11 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_SCLK_ISP_SPI0_CAM1, "sclk_isp_spi0_cam1", "div_sclk_isp_spi0_b", ENABLE_SCLK_TOP_CAM1, 0, 0, 0), + /* ENABLE_SCLK_TOP_DISP */ + GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp", + "mout_sclk_hdmi_spdif", ENABLE_SCLK_TOP_DISP, 0, + CLK_IGNORE_UNUSED, 0), + /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", ENABLE_SCLK_TOP_FSYS, 7, 0, 0), @@ -1521,11 +1526,6 @@ static struct samsung_gate_clock mif_gate_clks[] __initdata = { ENABLE_SCLK_MIF, 1, CLK_IGNORE_UNUSED, 0), GATE(CLK_SCLK_BUS_PLL_ATLAS, "sclk_bus_pll_atlas", "sclk_bus_pll", ENABLE_SCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), - - /* ENABLE_SCLK_TOP_DISP */ - GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp", - "mout_sclk_hdmi_spdif", ENABLE_SCLK_TOP_DISP, 0, - CLK_IGNORE_UNUSED, 0), }; static struct samsung_cmu_info mif_cmu_info __initdata = { diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 4853bc598b57..5bd80d5ecd0f 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -189,8 +189,9 @@ #define CLK_SCLK_ISP_UART_CAM1 250 #define CLK_SCLK_ISP_SPI1_CAM1 251 #define CLK_SCLK_ISP_SPI0_CAM1 252 +#define CLK_SCLK_HDMI_SPDIF_DISP 253 -#define TOP_NR_CLK 253 +#define TOP_NR_CLK 254 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -397,9 +398,8 @@ #define CLK_SCLK_BUS_PLL 198 #define CLK_SCLK_BUS_PLL_APOLLO 199 #define CLK_SCLK_BUS_PLL_ATLAS 200 -#define CLK_SCLK_HDMI_SPDIF_DISP 201 -#define MIF_NR_CLK 202 +#define MIF_NR_CLK 201 /* CMU_PERIC */ #define CLK_PCLK_SPI2 1 -- cgit v1.2.3 From cd67cd5eb25ae9a7bafbfd3d52d4c05e1d80af3b Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Fri, 6 Feb 2015 09:44:44 +0200 Subject: ipvs: use 64-bit rates in stats IPVS stats are limited to 2^(32-10) conns/s and packets/s, 2^(32-5) bytes/s. It is time to use 64 bits: * Change all conn/packet kernel counters to 64-bit and update them in u64_stats_update_{begin,end} section * In kernel use struct ip_vs_kstats instead of the user-space struct ip_vs_stats_user and use new func ip_vs_export_stats_user to export it to sockopt users to preserve compatibility with 32-bit values * Rename cpu counters "ustats" to "cnt" * To netlink users provide additionally 64-bit stats: IPVS_SVC_ATTR_STATS64 and IPVS_DEST_ATTR_STATS64. Old stats remain for old binaries. * We can use ip_vs_copy_stats in ip_vs_stats_percpu_show Thanks to Chris Caputo for providing initial patch for ip_vs_est.c Signed-off-by: Chris Caputo Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman --- include/net/ip_vs.h | 50 ++++++++---- include/uapi/linux/ip_vs.h | 7 +- net/netfilter/ipvs/ip_vs_core.c | 36 +++++---- net/netfilter/ipvs/ip_vs_ctl.c | 174 ++++++++++++++++++++++++++-------------- net/netfilter/ipvs/ip_vs_est.c | 102 ++++++++++++----------- 5 files changed, 226 insertions(+), 143 deletions(-) (limited to 'include') diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 615b20b58545..a627fe690c19 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -365,15 +365,15 @@ struct ip_vs_seq { /* counters per cpu */ struct ip_vs_counters { - __u32 conns; /* connections scheduled */ - __u32 inpkts; /* incoming packets */ - __u32 outpkts; /* outgoing packets */ + __u64 conns; /* connections scheduled */ + __u64 inpkts; /* incoming packets */ + __u64 outpkts; /* outgoing packets */ __u64 inbytes; /* incoming bytes */ __u64 outbytes; /* outgoing bytes */ }; /* Stats per cpu */ struct ip_vs_cpu_stats { - struct ip_vs_counters ustats; + struct ip_vs_counters cnt; struct u64_stats_sync syncp; }; @@ -383,23 +383,40 @@ struct ip_vs_estimator { u64 last_inbytes; u64 last_outbytes; - u32 last_conns; - u32 last_inpkts; - u32 last_outpkts; - - u32 cps; - u32 inpps; - u32 outpps; - u32 inbps; - u32 outbps; + u64 last_conns; + u64 last_inpkts; + u64 last_outpkts; + + u64 cps; + u64 inpps; + u64 outpps; + u64 inbps; + u64 outbps; +}; + +/* + * IPVS statistics object, 64-bit kernel version of struct ip_vs_stats_user + */ +struct ip_vs_kstats { + u64 conns; /* connections scheduled */ + u64 inpkts; /* incoming packets */ + u64 outpkts; /* outgoing packets */ + u64 inbytes; /* incoming bytes */ + u64 outbytes; /* outgoing bytes */ + + u64 cps; /* current connection rate */ + u64 inpps; /* current in packet rate */ + u64 outpps; /* current out packet rate */ + u64 inbps; /* current in byte rate */ + u64 outbps; /* current out byte rate */ }; struct ip_vs_stats { - struct ip_vs_stats_user ustats; /* statistics */ + struct ip_vs_kstats kstats; /* kernel statistics */ struct ip_vs_estimator est; /* estimator */ struct ip_vs_cpu_stats __percpu *cpustats; /* per cpu counters */ spinlock_t lock; /* spin lock */ - struct ip_vs_stats_user ustats0; /* reset values */ + struct ip_vs_kstats kstats0; /* reset values */ }; struct dst_entry; @@ -1388,8 +1405,7 @@ void ip_vs_sync_conn(struct net *net, struct ip_vs_conn *cp, int pkts); void ip_vs_start_estimator(struct net *net, struct ip_vs_stats *stats); void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats); void ip_vs_zero_estimator(struct ip_vs_stats *stats); -void ip_vs_read_estimator(struct ip_vs_stats_user *dst, - struct ip_vs_stats *stats); +void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats); /* Various IPVS packet transmitters (from ip_vs_xmit.c) */ int ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, diff --git a/include/uapi/linux/ip_vs.h b/include/uapi/linux/ip_vs.h index cabe95d5b461..3199243f2028 100644 --- a/include/uapi/linux/ip_vs.h +++ b/include/uapi/linux/ip_vs.h @@ -358,6 +358,8 @@ enum { IPVS_SVC_ATTR_PE_NAME, /* name of ct retriever */ + IPVS_SVC_ATTR_STATS64, /* nested attribute for service stats */ + __IPVS_SVC_ATTR_MAX, }; @@ -387,6 +389,8 @@ enum { IPVS_DEST_ATTR_ADDR_FAMILY, /* Address family of address */ + IPVS_DEST_ATTR_STATS64, /* nested attribute for dest stats */ + __IPVS_DEST_ATTR_MAX, }; @@ -410,7 +414,8 @@ enum { /* * Attributes used to describe service or destination entry statistics * - * Used inside nested attributes IPVS_SVC_ATTR_STATS and IPVS_DEST_ATTR_STATS + * Used inside nested attributes IPVS_SVC_ATTR_STATS, IPVS_DEST_ATTR_STATS, + * IPVS_SVC_ATTR_STATS64 and IPVS_DEST_ATTR_STATS64. */ enum { IPVS_STATS_ATTR_UNSPEC = 0, diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 990decba1fe4..c9470c86308f 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -119,24 +119,24 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb) struct ip_vs_service *svc; s = this_cpu_ptr(dest->stats.cpustats); - s->ustats.inpkts++; u64_stats_update_begin(&s->syncp); - s->ustats.inbytes += skb->len; + s->cnt.inpkts++; + s->cnt.inbytes += skb->len; u64_stats_update_end(&s->syncp); rcu_read_lock(); svc = rcu_dereference(dest->svc); s = this_cpu_ptr(svc->stats.cpustats); - s->ustats.inpkts++; u64_stats_update_begin(&s->syncp); - s->ustats.inbytes += skb->len; + s->cnt.inpkts++; + s->cnt.inbytes += skb->len; u64_stats_update_end(&s->syncp); rcu_read_unlock(); s = this_cpu_ptr(ipvs->tot_stats.cpustats); - s->ustats.inpkts++; u64_stats_update_begin(&s->syncp); - s->ustats.inbytes += skb->len; + s->cnt.inpkts++; + s->cnt.inbytes += skb->len; u64_stats_update_end(&s->syncp); } } @@ -153,24 +153,24 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb) struct ip_vs_service *svc; s = this_cpu_ptr(dest->stats.cpustats); - s->ustats.outpkts++; u64_stats_update_begin(&s->syncp); - s->ustats.outbytes += skb->len; + s->cnt.outpkts++; + s->cnt.outbytes += skb->len; u64_stats_update_end(&s->syncp); rcu_read_lock(); svc = rcu_dereference(dest->svc); s = this_cpu_ptr(svc->stats.cpustats); - s->ustats.outpkts++; u64_stats_update_begin(&s->syncp); - s->ustats.outbytes += skb->len; + s->cnt.outpkts++; + s->cnt.outbytes += skb->len; u64_stats_update_end(&s->syncp); rcu_read_unlock(); s = this_cpu_ptr(ipvs->tot_stats.cpustats); - s->ustats.outpkts++; u64_stats_update_begin(&s->syncp); - s->ustats.outbytes += skb->len; + s->cnt.outpkts++; + s->cnt.outbytes += skb->len; u64_stats_update_end(&s->syncp); } } @@ -183,13 +183,19 @@ ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc) struct ip_vs_cpu_stats *s; s = this_cpu_ptr(cp->dest->stats.cpustats); - s->ustats.conns++; + u64_stats_update_begin(&s->syncp); + s->cnt.conns++; + u64_stats_update_end(&s->syncp); s = this_cpu_ptr(svc->stats.cpustats); - s->ustats.conns++; + u64_stats_update_begin(&s->syncp); + s->cnt.conns++; + u64_stats_update_end(&s->syncp); s = this_cpu_ptr(ipvs->tot_stats.cpustats); - s->ustats.conns++; + u64_stats_update_begin(&s->syncp); + s->cnt.conns++; + u64_stats_update_end(&s->syncp); } diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index e55759056361..6fd60059faf0 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -729,9 +729,9 @@ static void ip_vs_trash_cleanup(struct net *net) } static void -ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src) +ip_vs_copy_stats(struct ip_vs_kstats *dst, struct ip_vs_stats *src) { -#define IP_VS_SHOW_STATS_COUNTER(c) dst->c = src->ustats.c - src->ustats0.c +#define IP_VS_SHOW_STATS_COUNTER(c) dst->c = src->kstats.c - src->kstats0.c spin_lock_bh(&src->lock); @@ -746,6 +746,21 @@ ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src) spin_unlock_bh(&src->lock); } +static void +ip_vs_export_stats_user(struct ip_vs_stats_user *dst, struct ip_vs_kstats *src) +{ + dst->conns = (u32)src->conns; + dst->inpkts = (u32)src->inpkts; + dst->outpkts = (u32)src->outpkts; + dst->inbytes = src->inbytes; + dst->outbytes = src->outbytes; + dst->cps = (u32)src->cps; + dst->inpps = (u32)src->inpps; + dst->outpps = (u32)src->outpps; + dst->inbps = (u32)src->inbps; + dst->outbps = (u32)src->outbps; +} + static void ip_vs_zero_stats(struct ip_vs_stats *stats) { @@ -753,7 +768,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats) /* get current counters as zero point, rates are zeroed */ -#define IP_VS_ZERO_STATS_COUNTER(c) stats->ustats0.c = stats->ustats.c +#define IP_VS_ZERO_STATS_COUNTER(c) stats->kstats0.c = stats->kstats.c IP_VS_ZERO_STATS_COUNTER(conns); IP_VS_ZERO_STATS_COUNTER(inpkts); @@ -2044,7 +2059,7 @@ static const struct file_operations ip_vs_info_fops = { static int ip_vs_stats_show(struct seq_file *seq, void *v) { struct net *net = seq_file_single_net(seq); - struct ip_vs_stats_user show; + struct ip_vs_kstats show; /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ seq_puts(seq, @@ -2053,17 +2068,22 @@ static int ip_vs_stats_show(struct seq_file *seq, void *v) " Conns Packets Packets Bytes Bytes\n"); ip_vs_copy_stats(&show, &net_ipvs(net)->tot_stats); - seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", show.conns, - show.inpkts, show.outpkts, - (unsigned long long) show.inbytes, - (unsigned long long) show.outbytes); - -/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ + seq_printf(seq, "%8LX %8LX %8LX %16LX %16LX\n\n", + (unsigned long long)show.conns, + (unsigned long long)show.inpkts, + (unsigned long long)show.outpkts, + (unsigned long long)show.inbytes, + (unsigned long long)show.outbytes); + +/* 01234567 01234567 01234567 0123456701234567 0123456701234567*/ seq_puts(seq, - " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); - seq_printf(seq, "%8X %8X %8X %16X %16X\n", - show.cps, show.inpps, show.outpps, - show.inbps, show.outbps); + " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); + seq_printf(seq, "%8LX %8LX %8LX %16LX %16LX\n", + (unsigned long long)show.cps, + (unsigned long long)show.inpps, + (unsigned long long)show.outpps, + (unsigned long long)show.inbps, + (unsigned long long)show.outbps); return 0; } @@ -2086,7 +2106,7 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) struct net *net = seq_file_single_net(seq); struct ip_vs_stats *tot_stats = &net_ipvs(net)->tot_stats; struct ip_vs_cpu_stats __percpu *cpustats = tot_stats->cpustats; - struct ip_vs_stats_user rates; + struct ip_vs_kstats kstats; int i; /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ @@ -2098,41 +2118,41 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) for_each_possible_cpu(i) { struct ip_vs_cpu_stats *u = per_cpu_ptr(cpustats, i); unsigned int start; - __u64 inbytes, outbytes; + u64 conns, inpkts, outpkts, inbytes, outbytes; do { start = u64_stats_fetch_begin_irq(&u->syncp); - inbytes = u->ustats.inbytes; - outbytes = u->ustats.outbytes; + conns = u->cnt.conns; + inpkts = u->cnt.inpkts; + outpkts = u->cnt.outpkts; + inbytes = u->cnt.inbytes; + outbytes = u->cnt.outbytes; } while (u64_stats_fetch_retry_irq(&u->syncp, start)); - seq_printf(seq, "%3X %8X %8X %8X %16LX %16LX\n", - i, u->ustats.conns, u->ustats.inpkts, - u->ustats.outpkts, (__u64)inbytes, - (__u64)outbytes); + seq_printf(seq, "%3X %8LX %8LX %8LX %16LX %16LX\n", + i, (u64)conns, (u64)inpkts, + (u64)outpkts, (u64)inbytes, + (u64)outbytes); } - spin_lock_bh(&tot_stats->lock); - - seq_printf(seq, " ~ %8X %8X %8X %16LX %16LX\n\n", - tot_stats->ustats.conns, tot_stats->ustats.inpkts, - tot_stats->ustats.outpkts, - (unsigned long long) tot_stats->ustats.inbytes, - (unsigned long long) tot_stats->ustats.outbytes); - - ip_vs_read_estimator(&rates, tot_stats); + ip_vs_copy_stats(&kstats, tot_stats); - spin_unlock_bh(&tot_stats->lock); + seq_printf(seq, " ~ %8LX %8LX %8LX %16LX %16LX\n\n", + (unsigned long long)kstats.conns, + (unsigned long long)kstats.inpkts, + (unsigned long long)kstats.outpkts, + (unsigned long long)kstats.inbytes, + (unsigned long long)kstats.outbytes); -/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ +/* ... 01234567 01234567 01234567 0123456701234567 0123456701234567 */ seq_puts(seq, - " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); - seq_printf(seq, " %8X %8X %8X %16X %16X\n", - rates.cps, - rates.inpps, - rates.outpps, - rates.inbps, - rates.outbps); + " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); + seq_printf(seq, " %8LX %8LX %8LX %16LX %16LX\n", + kstats.cps, + kstats.inpps, + kstats.outpps, + kstats.inbps, + kstats.outbps); return 0; } @@ -2400,6 +2420,7 @@ static void ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) { struct ip_vs_scheduler *sched; + struct ip_vs_kstats kstats; sched = rcu_dereference_protected(src->scheduler, 1); dst->protocol = src->protocol; @@ -2411,7 +2432,8 @@ ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) dst->timeout = src->timeout / HZ; dst->netmask = src->netmask; dst->num_dests = src->num_dests; - ip_vs_copy_stats(&dst->stats, &src->stats); + ip_vs_copy_stats(&kstats, &src->stats); + ip_vs_export_stats_user(&dst->stats, &kstats); } static inline int @@ -2485,6 +2507,7 @@ __ip_vs_get_dest_entries(struct net *net, const struct ip_vs_get_dests *get, int count = 0; struct ip_vs_dest *dest; struct ip_vs_dest_entry entry; + struct ip_vs_kstats kstats; memset(&entry, 0, sizeof(entry)); list_for_each_entry(dest, &svc->destinations, n_list) { @@ -2506,7 +2529,8 @@ __ip_vs_get_dest_entries(struct net *net, const struct ip_vs_get_dests *get, entry.activeconns = atomic_read(&dest->activeconns); entry.inactconns = atomic_read(&dest->inactconns); entry.persistconns = atomic_read(&dest->persistconns); - ip_vs_copy_stats(&entry.stats, &dest->stats); + ip_vs_copy_stats(&kstats, &dest->stats); + ip_vs_export_stats_user(&entry.stats, &kstats); if (copy_to_user(&uptr->entrytable[count], &entry, sizeof(entry))) { ret = -EFAULT; @@ -2798,25 +2822,51 @@ static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = { }; static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, - struct ip_vs_stats *stats) + struct ip_vs_kstats *kstats) +{ + struct nlattr *nl_stats = nla_nest_start(skb, container_type); + + if (!nl_stats) + return -EMSGSIZE; + + if (nla_put_u32(skb, IPVS_STATS_ATTR_CONNS, (u32)kstats->conns) || + nla_put_u32(skb, IPVS_STATS_ATTR_INPKTS, (u32)kstats->inpkts) || + nla_put_u32(skb, IPVS_STATS_ATTR_OUTPKTS, (u32)kstats->outpkts) || + nla_put_u64(skb, IPVS_STATS_ATTR_INBYTES, kstats->inbytes) || + nla_put_u64(skb, IPVS_STATS_ATTR_OUTBYTES, kstats->outbytes) || + nla_put_u32(skb, IPVS_STATS_ATTR_CPS, (u32)kstats->cps) || + nla_put_u32(skb, IPVS_STATS_ATTR_INPPS, (u32)kstats->inpps) || + nla_put_u32(skb, IPVS_STATS_ATTR_OUTPPS, (u32)kstats->outpps) || + nla_put_u32(skb, IPVS_STATS_ATTR_INBPS, (u32)kstats->inbps) || + nla_put_u32(skb, IPVS_STATS_ATTR_OUTBPS, (u32)kstats->outbps)) + goto nla_put_failure; + nla_nest_end(skb, nl_stats); + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, nl_stats); + return -EMSGSIZE; +} + +static int ip_vs_genl_fill_stats64(struct sk_buff *skb, int container_type, + struct ip_vs_kstats *kstats) { - struct ip_vs_stats_user ustats; struct nlattr *nl_stats = nla_nest_start(skb, container_type); + if (!nl_stats) return -EMSGSIZE; - ip_vs_copy_stats(&ustats, stats); - - if (nla_put_u32(skb, IPVS_STATS_ATTR_CONNS, ustats.conns) || - nla_put_u32(skb, IPVS_STATS_ATTR_INPKTS, ustats.inpkts) || - nla_put_u32(skb, IPVS_STATS_ATTR_OUTPKTS, ustats.outpkts) || - nla_put_u64(skb, IPVS_STATS_ATTR_INBYTES, ustats.inbytes) || - nla_put_u64(skb, IPVS_STATS_ATTR_OUTBYTES, ustats.outbytes) || - nla_put_u32(skb, IPVS_STATS_ATTR_CPS, ustats.cps) || - nla_put_u32(skb, IPVS_STATS_ATTR_INPPS, ustats.inpps) || - nla_put_u32(skb, IPVS_STATS_ATTR_OUTPPS, ustats.outpps) || - nla_put_u32(skb, IPVS_STATS_ATTR_INBPS, ustats.inbps) || - nla_put_u32(skb, IPVS_STATS_ATTR_OUTBPS, ustats.outbps)) + if (nla_put_u64(skb, IPVS_STATS_ATTR_CONNS, kstats->conns) || + nla_put_u64(skb, IPVS_STATS_ATTR_INPKTS, kstats->inpkts) || + nla_put_u64(skb, IPVS_STATS_ATTR_OUTPKTS, kstats->outpkts) || + nla_put_u64(skb, IPVS_STATS_ATTR_INBYTES, kstats->inbytes) || + nla_put_u64(skb, IPVS_STATS_ATTR_OUTBYTES, kstats->outbytes) || + nla_put_u64(skb, IPVS_STATS_ATTR_CPS, kstats->cps) || + nla_put_u64(skb, IPVS_STATS_ATTR_INPPS, kstats->inpps) || + nla_put_u64(skb, IPVS_STATS_ATTR_OUTPPS, kstats->outpps) || + nla_put_u64(skb, IPVS_STATS_ATTR_INBPS, kstats->inbps) || + nla_put_u64(skb, IPVS_STATS_ATTR_OUTBPS, kstats->outbps)) goto nla_put_failure; nla_nest_end(skb, nl_stats); @@ -2835,6 +2885,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb, struct nlattr *nl_service; struct ip_vs_flags flags = { .flags = svc->flags, .mask = ~0 }; + struct ip_vs_kstats kstats; nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE); if (!nl_service) @@ -2860,7 +2911,10 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb, nla_put_u32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ) || nla_put_be32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask)) goto nla_put_failure; - if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &svc->stats)) + ip_vs_copy_stats(&kstats, &svc->stats); + if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &kstats)) + goto nla_put_failure; + if (ip_vs_genl_fill_stats64(skb, IPVS_SVC_ATTR_STATS64, &kstats)) goto nla_put_failure; nla_nest_end(skb, nl_service); @@ -3032,6 +3086,7 @@ static struct ip_vs_service *ip_vs_genl_find_service(struct net *net, static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) { struct nlattr *nl_dest; + struct ip_vs_kstats kstats; nl_dest = nla_nest_start(skb, IPVS_CMD_ATTR_DEST); if (!nl_dest) @@ -3054,7 +3109,10 @@ static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) atomic_read(&dest->persistconns)) || nla_put_u16(skb, IPVS_DEST_ATTR_ADDR_FAMILY, dest->af)) goto nla_put_failure; - if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats)) + ip_vs_copy_stats(&kstats, &dest->stats); + if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &kstats)) + goto nla_put_failure; + if (ip_vs_genl_fill_stats64(skb, IPVS_DEST_ATTR_STATS64, &kstats)) goto nla_put_failure; nla_nest_end(skb, nl_dest); diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index 1425e9a924c4..ef0eb0a8d552 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c @@ -45,17 +45,19 @@ NOTES. - * The stored value for average bps is scaled by 2^5, so that maximal - rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10. + * Average bps is scaled by 2^5, while average pps and cps are scaled by 2^10. - * A lot code is taken from net/sched/estimator.c + * Netlink users can see 64-bit values but sockopt users are restricted + to 32-bit values for conns, packets, bps, cps and pps. + + * A lot of code is taken from net/core/gen_estimator.c */ /* * Make a summary from each cpu */ -static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum, +static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum, struct ip_vs_cpu_stats __percpu *stats) { int i; @@ -64,27 +66,31 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum, for_each_possible_cpu(i) { struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i); unsigned int start; - __u64 inbytes, outbytes; + u64 conns, inpkts, outpkts, inbytes, outbytes; + if (add) { - sum->conns += s->ustats.conns; - sum->inpkts += s->ustats.inpkts; - sum->outpkts += s->ustats.outpkts; do { start = u64_stats_fetch_begin(&s->syncp); - inbytes = s->ustats.inbytes; - outbytes = s->ustats.outbytes; + conns = s->cnt.conns; + inpkts = s->cnt.inpkts; + outpkts = s->cnt.outpkts; + inbytes = s->cnt.inbytes; + outbytes = s->cnt.outbytes; } while (u64_stats_fetch_retry(&s->syncp, start)); + sum->conns += conns; + sum->inpkts += inpkts; + sum->outpkts += outpkts; sum->inbytes += inbytes; sum->outbytes += outbytes; } else { add = true; - sum->conns = s->ustats.conns; - sum->inpkts = s->ustats.inpkts; - sum->outpkts = s->ustats.outpkts; do { start = u64_stats_fetch_begin(&s->syncp); - sum->inbytes = s->ustats.inbytes; - sum->outbytes = s->ustats.outbytes; + sum->conns = s->cnt.conns; + sum->inpkts = s->cnt.inpkts; + sum->outpkts = s->cnt.outpkts; + sum->inbytes = s->cnt.inbytes; + sum->outbytes = s->cnt.outbytes; } while (u64_stats_fetch_retry(&s->syncp, start)); } } @@ -95,10 +101,7 @@ static void estimation_timer(unsigned long arg) { struct ip_vs_estimator *e; struct ip_vs_stats *s; - u32 n_conns; - u32 n_inpkts, n_outpkts; - u64 n_inbytes, n_outbytes; - u32 rate; + u64 rate; struct net *net = (struct net *)arg; struct netns_ipvs *ipvs; @@ -108,33 +111,29 @@ static void estimation_timer(unsigned long arg) s = container_of(e, struct ip_vs_stats, est); spin_lock(&s->lock); - ip_vs_read_cpu_stats(&s->ustats, s->cpustats); - n_conns = s->ustats.conns; - n_inpkts = s->ustats.inpkts; - n_outpkts = s->ustats.outpkts; - n_inbytes = s->ustats.inbytes; - n_outbytes = s->ustats.outbytes; + ip_vs_read_cpu_stats(&s->kstats, s->cpustats); /* scaled by 2^10, but divided 2 seconds */ - rate = (n_conns - e->last_conns) << 9; - e->last_conns = n_conns; - e->cps += ((long)rate - (long)e->cps) >> 2; - - rate = (n_inpkts - e->last_inpkts) << 9; - e->last_inpkts = n_inpkts; - e->inpps += ((long)rate - (long)e->inpps) >> 2; - - rate = (n_outpkts - e->last_outpkts) << 9; - e->last_outpkts = n_outpkts; - e->outpps += ((long)rate - (long)e->outpps) >> 2; - - rate = (n_inbytes - e->last_inbytes) << 4; - e->last_inbytes = n_inbytes; - e->inbps += ((long)rate - (long)e->inbps) >> 2; - - rate = (n_outbytes - e->last_outbytes) << 4; - e->last_outbytes = n_outbytes; - e->outbps += ((long)rate - (long)e->outbps) >> 2; + rate = (s->kstats.conns - e->last_conns) << 9; + e->last_conns = s->kstats.conns; + e->cps += ((s64)rate - (s64)e->cps) >> 2; + + rate = (s->kstats.inpkts - e->last_inpkts) << 9; + e->last_inpkts = s->kstats.inpkts; + e->inpps += ((s64)rate - (s64)e->inpps) >> 2; + + rate = (s->kstats.outpkts - e->last_outpkts) << 9; + e->last_outpkts = s->kstats.outpkts; + e->outpps += ((s64)rate - (s64)e->outpps) >> 2; + + /* scaled by 2^5, but divided 2 seconds */ + rate = (s->kstats.inbytes - e->last_inbytes) << 4; + e->last_inbytes = s->kstats.inbytes; + e->inbps += ((s64)rate - (s64)e->inbps) >> 2; + + rate = (s->kstats.outbytes - e->last_outbytes) << 4; + e->last_outbytes = s->kstats.outbytes; + e->outbps += ((s64)rate - (s64)e->outbps) >> 2; spin_unlock(&s->lock); } spin_unlock(&ipvs->est_lock); @@ -166,14 +165,14 @@ void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats) void ip_vs_zero_estimator(struct ip_vs_stats *stats) { struct ip_vs_estimator *est = &stats->est; - struct ip_vs_stats_user *u = &stats->ustats; + struct ip_vs_kstats *k = &stats->kstats; /* reset counters, caller must hold the stats->lock lock */ - est->last_inbytes = u->inbytes; - est->last_outbytes = u->outbytes; - est->last_conns = u->conns; - est->last_inpkts = u->inpkts; - est->last_outpkts = u->outpkts; + est->last_inbytes = k->inbytes; + est->last_outbytes = k->outbytes; + est->last_conns = k->conns; + est->last_inpkts = k->inpkts; + est->last_outpkts = k->outpkts; est->cps = 0; est->inpps = 0; est->outpps = 0; @@ -182,8 +181,7 @@ void ip_vs_zero_estimator(struct ip_vs_stats *stats) } /* Get decoded rates */ -void ip_vs_read_estimator(struct ip_vs_stats_user *dst, - struct ip_vs_stats *stats) +void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats) { struct ip_vs_estimator *e = &stats->est; -- cgit v1.2.3 From ac37e2515c1a89c477459a2020b6bfdedabdb91b Mon Sep 17 00:00:00 2001 From: huaibin Wang Date: Wed, 11 Feb 2015 18:10:36 +0100 Subject: xfrm: release dst_orig in case of error in xfrm_lookup() dst_orig should be released on error. Function like __xfrm_route_forward() expects that behavior. Since a recent commit, xfrm_lookup() may also be called by xfrm_lookup_route(), which expects the opposite. Let's introduce a new flag (XFRM_LOOKUP_KEEP_DST_REF) to tell what should be done in case of error. Fixes: f92ee61982d("xfrm: Generate blackhole routes only from route lookup functions") Signed-off-by: huaibin Wang Signed-off-by: Nicolas Dichtel Signed-off-by: Steffen Klassert --- include/net/dst.h | 1 + net/xfrm/xfrm_policy.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/dst.h b/include/net/dst.h index a8ae4e760778..0fb99a26e973 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -481,6 +481,7 @@ void dst_init(void); enum { XFRM_LOOKUP_ICMP = 1 << 0, XFRM_LOOKUP_QUEUE = 1 << 1, + XFRM_LOOKUP_KEEP_DST_REF = 1 << 2, }; struct flowi; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index cee479bc655c..638af0655aaf 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2269,11 +2269,9 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, * have the xfrm_state's. We need to wait for KM to * negotiate new SA's or bail out with error.*/ if (net->xfrm.sysctl_larval_drop) { - dst_release(dst); - xfrm_pols_put(pols, drop_pols); XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); - - return ERR_PTR(-EREMOTE); + err = -EREMOTE; + goto error; } err = -EAGAIN; @@ -2324,7 +2322,8 @@ nopol: error: dst_release(dst); dropdst: - dst_release(dst_orig); + if (!(flags & XFRM_LOOKUP_KEEP_DST_REF)) + dst_release(dst_orig); xfrm_pols_put(pols, drop_pols); return ERR_PTR(err); } @@ -2338,7 +2337,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, struct sock *sk, int flags) { struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk, - flags | XFRM_LOOKUP_QUEUE); + flags | XFRM_LOOKUP_QUEUE | + XFRM_LOOKUP_KEEP_DST_REF); if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE) return make_blackhole(net, dst_orig->ops->family, dst_orig); -- cgit v1.2.3 From 72496edcf85e048b4c5373d518e4f27938d9594e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Feb 2015 22:39:51 +0100 Subject: ALSA: seq: Don't compile snd_seq_device_load_drivers() for built-in Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 4 ++++ sound/core/seq/seq_device.c | 9 +++------ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index 2b5f24cc7548..d52433563da2 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -67,7 +67,11 @@ struct snd_seq_dev_ops { /* * prototypes */ +#ifdef CONFIG_MODULES void snd_seq_device_load_drivers(void); +#else +#define snd_seq_device_load_drivers() +#endif int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result); int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize); int snd_seq_device_unregister_driver(char *id); diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index a752a79a8d3a..075a66c0cc6a 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -198,19 +198,16 @@ void snd_seq_autoload_init(void) #endif } EXPORT_SYMBOL(snd_seq_autoload_init); -#else -#define try_autoload(ops) /* NOP */ -#endif - void snd_seq_device_load_drivers(void) { -#ifdef CONFIG_MODULES queue_autoload_drivers(); flush_work(&autoload_work); -#endif } EXPORT_SYMBOL(snd_seq_device_load_drivers); +#else +#define try_autoload(ops) /* NOP */ +#endif /* * register a sequencer device -- cgit v1.2.3 From 7c37ae5c625aaa4836466cfaea829a3199dfc571 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 10:51:59 +0100 Subject: ALSA: seq: Rewrite sequencer device binding with standard bus We've used the old house-made code for binding the sequencer device and driver. This can be far better implemented with the standard bus nowadays. This patch refactors the whole sequencer binding code with the bus /sys/bus/snd_seq. The devices appear as id-card-device on this bus and are bound with the drivers corresponding to the given id like the former implementation. The module autoload is also kept like before. There is no change in API functions by this patch, and almost all transitions are kept inside seq_device.c. The proc file output will change slightly but kept compatible as much as possible. Further integration works will follow in later patches. Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 3 + sound/core/seq/seq_device.c | 541 ++++++++++++++------------------------------ 2 files changed, 170 insertions(+), 374 deletions(-) (limited to 'include') diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index d52433563da2..ea256b825146 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -43,8 +43,11 @@ struct snd_seq_device { void *private_data; /* private data for the caller */ void (*private_free)(struct snd_seq_device *device); struct list_head list; /* link to next device */ + struct device dev; }; +#define to_seq_dev(_dev) \ + container_of(_dev, struct snd_seq_device, dev) /* driver operators * init_device: diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 075a66c0cc6a..d3320ffe43c2 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -36,6 +36,7 @@ * */ +#include #include #include #include @@ -51,77 +52,57 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("ALSA sequencer device management"); MODULE_LICENSE("GPL"); -/* driver state */ -#define DRIVER_EMPTY 0 -#define DRIVER_LOADED (1<<0) -#define DRIVER_REQUESTED (1<<1) -#define DRIVER_LOCKED (1<<2) -#define DRIVER_REQUESTING (1<<3) +struct snd_seq_driver { + struct device_driver driver; + char id[ID_LEN]; + int argsize; + struct snd_seq_dev_ops ops; +}; -struct ops_list { - char id[ID_LEN]; /* driver id */ - int driver; /* driver state */ - int used; /* reference counter */ - int argsize; /* argument size */ +#define to_seq_drv(_drv) \ + container_of(_drv, struct snd_seq_driver, driver) - /* operators */ - struct snd_seq_dev_ops ops; +/* + * bus definition + */ +static int snd_seq_bus_match(struct device *dev, struct device_driver *drv) +{ + struct snd_seq_device *sdev = to_seq_dev(dev); + struct snd_seq_driver *sdrv = to_seq_drv(drv); - /* registered devices */ - struct list_head dev_list; /* list of devices */ - int num_devices; /* number of associated devices */ - int num_init_devices; /* number of initialized devices */ - struct mutex reg_mutex; + return strcmp(sdrv->id, sdev->id) == 0 && + sdrv->argsize == sdev->argsize; +} - struct list_head list; /* next driver */ +static struct bus_type snd_seq_bus_type = { + .name = "snd_seq", + .match = snd_seq_bus_match, }; - -static LIST_HEAD(opslist); -static int num_ops; -static DEFINE_MUTEX(ops_mutex); +/* + * proc interface -- just for compatibility + */ #ifdef CONFIG_PROC_FS static struct snd_info_entry *info_entry; -#endif -/* - * prototypes - */ -static int snd_seq_device_free(struct snd_seq_device *dev); -static int snd_seq_device_dev_free(struct snd_device *device); -static int snd_seq_device_dev_register(struct snd_device *device); -static int snd_seq_device_dev_disconnect(struct snd_device *device); - -static int init_device(struct snd_seq_device *dev, struct ops_list *ops); -static int free_device(struct snd_seq_device *dev, struct ops_list *ops); -static struct ops_list *find_driver(char *id, int create_if_empty); -static struct ops_list *create_driver(char *id); -static void unlock_driver(struct ops_list *ops); -static void remove_drivers(void); +static int print_dev_info(struct device *dev, void *data) +{ + struct snd_seq_device *sdev = to_seq_dev(dev); + struct snd_info_buffer *buffer = data; -/* - * show all drivers and their status - */ + snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id, + dev->driver ? "loaded" : "empty", + dev->driver ? 1 : 0); + return 0; +} -#ifdef CONFIG_PROC_FS static void snd_seq_device_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", - ops->id, - ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), - ops->driver & DRIVER_REQUESTED ? ",requested" : "", - ops->driver & DRIVER_LOCKED ? ",locked" : "", - ops->num_devices); - } - mutex_unlock(&ops_mutex); + bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info); } #endif - + /* * load all registered drivers (called from seq_clientmgr.c) */ @@ -141,52 +122,29 @@ void snd_seq_autoload_unlock(void) } EXPORT_SYMBOL(snd_seq_autoload_unlock); -static void autoload_drivers(void) +static int request_seq_drv(struct device *dev, void *data) { - /* avoid reentrance */ - if (atomic_inc_return(&snd_seq_in_init) == 1) { - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - if ((ops->driver & DRIVER_REQUESTING) && - !(ops->driver & DRIVER_REQUESTED)) { - ops->used++; - mutex_unlock(&ops_mutex); - ops->driver |= DRIVER_REQUESTED; - request_module("snd-%s", ops->id); - mutex_lock(&ops_mutex); - ops->used--; - } - } - mutex_unlock(&ops_mutex); - } - atomic_dec(&snd_seq_in_init); -} + struct snd_seq_device *sdev = to_seq_dev(dev); -static void call_autoload(struct work_struct *work) -{ - autoload_drivers(); + if (!dev->driver) + request_module("snd-%s", sdev->id); + return 0; } -static DECLARE_WORK(autoload_work, call_autoload); - -static void try_autoload(struct ops_list *ops) +static void autoload_drivers(struct work_struct *work) { - if (!ops->driver) { - ops->driver |= DRIVER_REQUESTING; - schedule_work(&autoload_work); - } + /* avoid reentrance */ + if (atomic_inc_return(&snd_seq_in_init) == 1) + bus_for_each_dev(&snd_seq_bus_type, NULL, NULL, + request_seq_drv); + atomic_dec(&snd_seq_in_init); } +static DECLARE_WORK(autoload_work, autoload_drivers); + static void queue_autoload_drivers(void) { - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) - try_autoload(ops); - mutex_unlock(&ops_mutex); + schedule_work(&autoload_work); } void snd_seq_autoload_init(void) @@ -206,9 +164,50 @@ void snd_seq_device_load_drivers(void) } EXPORT_SYMBOL(snd_seq_device_load_drivers); #else -#define try_autoload(ops) /* NOP */ +#define queue_autoload_drivers() /* NOP */ #endif +/* + * device management + */ +static int snd_seq_device_dev_free(struct snd_device *device) +{ + struct snd_seq_device *dev = device->device_data; + + put_device(&dev->dev); + return 0; +} + +static int snd_seq_device_dev_register(struct snd_device *device) +{ + struct snd_seq_device *dev = device->device_data; + int err; + + err = device_add(&dev->dev); + if (err < 0) + return err; + if (!dev->dev.driver) + queue_autoload_drivers(); + return 0; +} + +static int snd_seq_device_dev_disconnect(struct snd_device *device) +{ + struct snd_seq_device *dev = device->device_data; + + device_del(&dev->dev); + return 0; +} + +static void snd_seq_dev_release(struct device *dev) +{ + struct snd_seq_device *sdev = to_seq_dev(dev); + + if (sdev->private_free) + sdev->private_free(sdev); + kfree(sdev); +} + /* * register a sequencer device * card = card info @@ -220,7 +219,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result) { struct snd_seq_device *dev; - struct ops_list *ops; int err; static struct snd_device_ops dops = { .dev_free = snd_seq_device_dev_free, @@ -234,15 +232,9 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, if (snd_BUG_ON(!id)) return -EINVAL; - ops = find_driver(id, 1); - if (ops == NULL) - return -ENOMEM; - - dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL); - if (dev == NULL) { - unlock_driver(ops); + dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL); + if (!dev) return -ENOMEM; - } /* set up device info */ dev->card = card; @@ -251,20 +243,19 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, dev->argsize = argsize; dev->status = SNDRV_SEQ_DEVICE_FREE; - /* add this device to the list */ - mutex_lock(&ops->reg_mutex); - list_add_tail(&dev->list, &ops->dev_list); - ops->num_devices++; - mutex_unlock(&ops->reg_mutex); + device_initialize(&dev->dev); + dev->dev.parent = &card->card_dev; + dev->dev.bus = &snd_seq_bus_type; + dev->dev.release = snd_seq_dev_release; + dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device); - if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { - snd_seq_device_free(dev); + /* add this device to the list */ + err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops); + if (err < 0) { + put_device(&dev->dev); return err; } - try_autoload(ops); - unlock_driver(ops); - if (result) *result = dev; @@ -273,82 +264,33 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, EXPORT_SYMBOL(snd_seq_device_new); /* - * free the existing device - */ -static int snd_seq_device_free(struct snd_seq_device *dev) -{ - struct ops_list *ops; - - if (snd_BUG_ON(!dev)) - return -EINVAL; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENXIO; - - /* remove the device from the list */ - mutex_lock(&ops->reg_mutex); - list_del(&dev->list); - ops->num_devices--; - mutex_unlock(&ops->reg_mutex); - - free_device(dev, ops); - if (dev->private_free) - dev->private_free(dev); - kfree(dev); - - unlock_driver(ops); - - return 0; -} - -static int snd_seq_device_dev_free(struct snd_device *device) -{ - struct snd_seq_device *dev = device->device_data; - return snd_seq_device_free(dev); -} - -/* - * register the device + * driver binding - just pass to each driver callback */ -static int snd_seq_device_dev_register(struct snd_device *device) +static int snd_seq_drv_probe(struct device *dev) { - struct snd_seq_device *dev = device->device_data; - struct ops_list *ops; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENOENT; - - /* initialize this device if the corresponding driver was - * already loaded - */ - if (ops->driver & DRIVER_LOADED) - init_device(dev, ops); + struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); + struct snd_seq_device *sdev = to_seq_dev(dev); + int err; - unlock_driver(ops); + err = sdrv->ops.init_device(sdev); + if (err < 0) + return err; + sdev->status = SNDRV_SEQ_DEVICE_REGISTERED; return 0; } -EXPORT_SYMBOL(snd_seq_device_register_driver); -/* - * disconnect the device - */ -static int snd_seq_device_dev_disconnect(struct snd_device *device) +static int snd_seq_drv_remove(struct device *dev) { - struct snd_seq_device *dev = device->device_data; - struct ops_list *ops; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENOENT; - - free_device(dev, ops); + struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); + struct snd_seq_device *sdev = to_seq_dev(dev); + int err; - unlock_driver(ops); + err = sdrv->ops.free_device(sdev); + if (err < 0) + return err; + sdev->status = SNDRV_SEQ_DEVICE_FREE; return 0; } -EXPORT_SYMBOL(snd_seq_device_unregister_driver); /* * register device driver @@ -358,226 +300,66 @@ EXPORT_SYMBOL(snd_seq_device_unregister_driver); int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize) { - struct ops_list *ops; - struct snd_seq_device *dev; + struct snd_seq_driver *sdrv; + int err; if (id == NULL || entry == NULL || entry->init_device == NULL || entry->free_device == NULL) return -EINVAL; - ops = find_driver(id, 1); - if (ops == NULL) + sdrv = kzalloc(sizeof(*sdrv), GFP_KERNEL); + if (!sdrv) return -ENOMEM; - if (ops->driver & DRIVER_LOADED) { - pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id); - unlock_driver(ops); - return -EBUSY; - } - - mutex_lock(&ops->reg_mutex); - /* copy driver operators */ - ops->ops = *entry; - ops->driver |= DRIVER_LOADED; - ops->argsize = argsize; - /* initialize existing devices if necessary */ - list_for_each_entry(dev, &ops->dev_list, list) { - init_device(dev, ops); - } - mutex_unlock(&ops->reg_mutex); - - unlock_driver(ops); - - return 0; + sdrv->driver.name = id; + sdrv->driver.bus = &snd_seq_bus_type; + sdrv->driver.probe = snd_seq_drv_probe; + sdrv->driver.remove = snd_seq_drv_remove; + strlcpy(sdrv->id, id, sizeof(sdrv->id)); + sdrv->argsize = argsize; + sdrv->ops = *entry; + + err = driver_register(&sdrv->driver); + if (err < 0) + kfree(sdrv); + return err; } +EXPORT_SYMBOL(snd_seq_device_register_driver); - -/* - * create driver record +/* callback to find a specific driver; data is a pointer to the id string ptr. + * when the id matches, store the driver pointer in return and break the loop. */ -static struct ops_list * create_driver(char *id) +static int find_drv(struct device_driver *drv, void *data) { - struct ops_list *ops; - - ops = kzalloc(sizeof(*ops), GFP_KERNEL); - if (ops == NULL) - return ops; - - /* set up driver entry */ - strlcpy(ops->id, id, sizeof(ops->id)); - mutex_init(&ops->reg_mutex); - /* - * The ->reg_mutex locking rules are per-driver, so we create - * separate per-driver lock classes: - */ - lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id); - - ops->driver = DRIVER_EMPTY; - INIT_LIST_HEAD(&ops->dev_list); - /* lock this instance */ - ops->used = 1; - - /* register driver entry */ - mutex_lock(&ops_mutex); - list_add_tail(&ops->list, &opslist); - num_ops++; - mutex_unlock(&ops_mutex); - - return ops; -} + struct snd_seq_driver *sdrv = to_seq_drv(drv); + void **ptr = (void **)data; + if (strcmp(sdrv->id, *ptr)) + return 0; /* id don't match, continue the loop */ + *ptr = sdrv; + return 1; /* break the loop */ +} /* * unregister the specified driver */ int snd_seq_device_unregister_driver(char *id) { - struct ops_list *ops; - struct snd_seq_device *dev; + struct snd_seq_driver *sdrv = (struct snd_seq_driver *)id; - ops = find_driver(id, 0); - if (ops == NULL) + if (!bus_for_each_drv(&snd_seq_bus_type, NULL, &sdrv, find_drv)) return -ENXIO; - if (! (ops->driver & DRIVER_LOADED) || - (ops->driver & DRIVER_LOCKED)) { - pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n", - id, ops->driver); - unlock_driver(ops); - return -EBUSY; - } - - /* close and release all devices associated with this driver */ - mutex_lock(&ops->reg_mutex); - ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ - list_for_each_entry(dev, &ops->dev_list, list) { - free_device(dev, ops); - } - - ops->driver = 0; - if (ops->num_init_devices > 0) - pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n", - ops->num_init_devices); - mutex_unlock(&ops->reg_mutex); - - unlock_driver(ops); - - /* remove empty driver entries */ - remove_drivers(); - + driver_unregister(&sdrv->driver); + kfree(sdrv); return 0; } - - -/* - * remove empty driver entries - */ -static void remove_drivers(void) -{ - struct list_head *head; - - mutex_lock(&ops_mutex); - head = opslist.next; - while (head != &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); - if (! (ops->driver & DRIVER_LOADED) && - ops->used == 0 && ops->num_devices == 0) { - head = head->next; - list_del(&ops->list); - kfree(ops); - num_ops--; - } else - head = head->next; - } - mutex_unlock(&ops_mutex); -} - -/* - * initialize the device - call init_device operator - */ -static int init_device(struct snd_seq_device *dev, struct ops_list *ops) -{ - if (! (ops->driver & DRIVER_LOADED)) - return 0; /* driver is not loaded yet */ - if (dev->status != SNDRV_SEQ_DEVICE_FREE) - return 0; /* already initialized */ - if (ops->argsize != dev->argsize) { - pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n", - dev->name, ops->id, ops->argsize, dev->argsize); - return -EINVAL; - } - if (ops->ops.init_device(dev) >= 0) { - dev->status = SNDRV_SEQ_DEVICE_REGISTERED; - ops->num_init_devices++; - } else { - pr_err("ALSA: seq: init_device failed: %s: %s\n", - dev->name, dev->id); - } - - return 0; -} - -/* - * release the device - call free_device operator - */ -static int free_device(struct snd_seq_device *dev, struct ops_list *ops) -{ - int result; - - if (! (ops->driver & DRIVER_LOADED)) - return 0; /* driver is not loaded yet */ - if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED) - return 0; /* not registered */ - if (ops->argsize != dev->argsize) { - pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n", - dev->name, ops->id, ops->argsize, dev->argsize); - return -EINVAL; - } - if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { - dev->status = SNDRV_SEQ_DEVICE_FREE; - dev->driver_data = NULL; - ops->num_init_devices--; - } else { - pr_err("ALSA: seq: free_device failed: %s: %s\n", - dev->name, dev->id); - } - - return 0; -} - -/* - * find the matching driver with given id - */ -static struct ops_list * find_driver(char *id, int create_if_empty) -{ - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - if (strcmp(ops->id, id) == 0) { - ops->used++; - mutex_unlock(&ops_mutex); - return ops; - } - } - mutex_unlock(&ops_mutex); - if (create_if_empty) - return create_driver(id); - return NULL; -} - -static void unlock_driver(struct ops_list *ops) -{ - mutex_lock(&ops_mutex); - ops->used--; - mutex_unlock(&ops_mutex); -} - +EXPORT_SYMBOL(snd_seq_device_unregister_driver); /* * module part */ -static int __init alsa_seq_device_init(void) +static int __init seq_dev_proc_init(void) { #ifdef CONFIG_PROC_FS info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", @@ -594,17 +376,28 @@ static int __init alsa_seq_device_init(void) return 0; } +static int __init alsa_seq_device_init(void) +{ + int err; + + err = bus_register(&snd_seq_bus_type); + if (err < 0) + return err; + err = seq_dev_proc_init(); + if (err < 0) + bus_unregister(&snd_seq_bus_type); + return err; +} + static void __exit alsa_seq_device_exit(void) { #ifdef CONFIG_MODULES cancel_work_sync(&autoload_work); #endif - remove_drivers(); #ifdef CONFIG_PROC_FS snd_info_free_entry(info_entry); #endif - if (num_ops) - pr_err("ALSA: seq: drivers not released (%d)\n", num_ops); + bus_unregister(&snd_seq_bus_type); } module_init(alsa_seq_device_init) -- cgit v1.2.3 From af03c243a1f014145dae34368fe975b2f08ed964 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 13:40:50 +0100 Subject: ALSA: seq: Clean up device and driver structs Use const string pointer instead of copying the id string to each object. Also drop the status and list fields of snd_seq_device struct that are no longer used. Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 18 ++++++------------ sound/core/seq/seq_device.c | 31 ++++++++++--------------------- 2 files changed, 16 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index ea256b825146..b13cd2930d32 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -25,24 +25,16 @@ * registered device information */ -#define ID_LEN 32 - -/* status flag */ -#define SNDRV_SEQ_DEVICE_FREE 0 -#define SNDRV_SEQ_DEVICE_REGISTERED 1 - struct snd_seq_device { /* device info */ struct snd_card *card; /* sound card */ int device; /* device number */ - char id[ID_LEN]; /* driver id */ + const char *id; /* driver id */ char name[80]; /* device name */ int argsize; /* size of the argument */ void *driver_data; /* private data for driver */ - int status; /* flag - read only */ void *private_data; /* private data for the caller */ void (*private_free)(struct snd_seq_device *device); - struct list_head list; /* link to next device */ struct device dev; }; @@ -75,9 +67,11 @@ void snd_seq_device_load_drivers(void); #else #define snd_seq_device_load_drivers() #endif -int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result); -int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize); -int snd_seq_device_unregister_driver(char *id); +int snd_seq_device_new(struct snd_card *card, int device, const char *id, + int argsize, struct snd_seq_device **result); +int snd_seq_device_register_driver(const char *id, + struct snd_seq_dev_ops *entry, int argsize); +int snd_seq_device_unregister_driver(const char *id); #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device)) diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index d3320ffe43c2..49daf6e3a387 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -54,7 +54,7 @@ MODULE_LICENSE("GPL"); struct snd_seq_driver { struct device_driver driver; - char id[ID_LEN]; + const char *id; int argsize; struct snd_seq_dev_ops ops; }; @@ -215,8 +215,8 @@ static void snd_seq_dev_release(struct device *dev) * id = id of driver * result = return pointer (NULL allowed if unnecessary) */ -int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, - struct snd_seq_device **result) +int snd_seq_device_new(struct snd_card *card, int device, const char *id, + int argsize, struct snd_seq_device **result) { struct snd_seq_device *dev; int err; @@ -239,9 +239,8 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, /* set up device info */ dev->card = card; dev->device = device; - strlcpy(dev->id, id, sizeof(dev->id)); + dev->id = id; dev->argsize = argsize; - dev->status = SNDRV_SEQ_DEVICE_FREE; device_initialize(&dev->dev); dev->dev.parent = &card->card_dev; @@ -270,26 +269,16 @@ static int snd_seq_drv_probe(struct device *dev) { struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); struct snd_seq_device *sdev = to_seq_dev(dev); - int err; - err = sdrv->ops.init_device(sdev); - if (err < 0) - return err; - sdev->status = SNDRV_SEQ_DEVICE_REGISTERED; - return 0; + return sdrv->ops.init_device(sdev); } static int snd_seq_drv_remove(struct device *dev) { struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); struct snd_seq_device *sdev = to_seq_dev(dev); - int err; - err = sdrv->ops.free_device(sdev); - if (err < 0) - return err; - sdev->status = SNDRV_SEQ_DEVICE_FREE; - return 0; + return sdrv->ops.free_device(sdev); } /* @@ -297,8 +286,8 @@ static int snd_seq_drv_remove(struct device *dev) * id = driver id * entry = driver operators - duplicated to each instance */ -int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, - int argsize) +int snd_seq_device_register_driver(const char *id, + struct snd_seq_dev_ops *entry, int argsize) { struct snd_seq_driver *sdrv; int err; @@ -315,7 +304,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, sdrv->driver.bus = &snd_seq_bus_type; sdrv->driver.probe = snd_seq_drv_probe; sdrv->driver.remove = snd_seq_drv_remove; - strlcpy(sdrv->id, id, sizeof(sdrv->id)); + sdrv->id = id; sdrv->argsize = argsize; sdrv->ops = *entry; @@ -343,7 +332,7 @@ static int find_drv(struct device_driver *drv, void *data) /* * unregister the specified driver */ -int snd_seq_device_unregister_driver(char *id) +int snd_seq_device_unregister_driver(const char *id) { struct snd_seq_driver *sdrv = (struct snd_seq_driver *)id; -- cgit v1.2.3 From 056622053b8ae02978678ac1321b5bd956e7c812 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 13:43:22 +0100 Subject: ALSA: seq: Define driver object in each driver This patch moves the driver object initialization and allocation to each driver's module init/exit code like other normal drivers. The snd_seq_driver struct is now published in seq_device.h, and each driver is responsible to define it with proper driver attributes (name, probe and remove) with snd_seq_driver specific attributes as id and argsize fields. The helper functions snd_seq_driver_register(), snd_seq_driver_unregister() and module_snd_seq_driver() are used for simplifying codes. Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 27 +++++++---- sound/core/seq/oss/seq_oss.c | 20 +++++--- sound/core/seq/oss/seq_oss_synth.c | 6 ++- sound/core/seq/oss/seq_oss_synth.h | 4 +- sound/core/seq/seq_device.c | 93 ++++---------------------------------- sound/core/seq/seq_midi.c | 28 ++++++++---- sound/drivers/opl3/opl3_seq.c | 34 ++++++-------- sound/drivers/opl4/opl4_seq.c | 33 ++++++-------- sound/isa/sb/emu8000_synth.c | 35 ++++++-------- sound/pci/emu10k1/emu10k1_synth.c | 35 ++++++-------- 10 files changed, 124 insertions(+), 191 deletions(-) (limited to 'include') diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index b13cd2930d32..ddc0d504cf39 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -41,8 +41,10 @@ struct snd_seq_device { #define to_seq_dev(_dev) \ container_of(_dev, struct snd_seq_device, dev) +/* sequencer driver */ + /* driver operators - * init_device: + * probe: * Initialize the device with given parameters. * Typically, * 1. call snd_hwdep_new @@ -50,15 +52,19 @@ struct snd_seq_device { * 3. call snd_hwdep_register * 4. store the instance to dev->driver_data pointer. * - * free_device: + * remove: * Release the private data. * Typically, call snd_device_free(dev->card, dev->driver_data) */ -struct snd_seq_dev_ops { - int (*init_device)(struct snd_seq_device *dev); - int (*free_device)(struct snd_seq_device *dev); +struct snd_seq_driver { + struct device_driver driver; + char *id; + int argsize; }; +#define to_seq_drv(_drv) \ + container_of(_drv, struct snd_seq_driver, driver) + /* * prototypes */ @@ -69,12 +75,17 @@ void snd_seq_device_load_drivers(void); #endif int snd_seq_device_new(struct snd_card *card, int device, const char *id, int argsize, struct snd_seq_device **result); -int snd_seq_device_register_driver(const char *id, - struct snd_seq_dev_ops *entry, int argsize); -int snd_seq_device_unregister_driver(const char *id); #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device)) +int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv, + struct module *mod); +#define snd_seq_driver_register(drv) \ + __snd_seq_driver_register(drv, THIS_MODULE) +void snd_seq_driver_unregister(struct snd_seq_driver *drv); + +#define module_snd_seq_driver(drv) \ + module_driver(drv, snd_seq_driver_register, snd_seq_driver_unregister) /* * id strings for generic devices diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 16d42679e43f..ae1814aa767e 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -65,13 +65,19 @@ static unsigned int odev_poll(struct file *file, poll_table * wait); * module interface */ +static struct snd_seq_driver seq_oss_synth_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_seq_oss_synth_probe, + .remove = snd_seq_oss_synth_remove, + }, + .id = SNDRV_SEQ_DEV_ID_OSS, + .argsize = sizeof(struct snd_seq_oss_reg), +}; + static int __init alsa_seq_oss_init(void) { int rc; - static struct snd_seq_dev_ops ops = { - snd_seq_oss_synth_register, - snd_seq_oss_synth_unregister, - }; snd_seq_autoload_lock(); if ((rc = register_device()) < 0) @@ -86,8 +92,8 @@ static int __init alsa_seq_oss_init(void) goto error; } - if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops, - sizeof(struct snd_seq_oss_reg))) < 0) { + rc = snd_seq_driver_register(&seq_oss_synth_driver); + if (rc < 0) { snd_seq_oss_delete_client(); unregister_proc(); unregister_device(); @@ -104,7 +110,7 @@ static int __init alsa_seq_oss_init(void) static void __exit alsa_seq_oss_exit(void) { - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS); + snd_seq_driver_unregister(&seq_oss_synth_driver); snd_seq_oss_delete_client(); unregister_proc(); unregister_device(); diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 701feb71b700..835edc80f918 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -98,8 +98,9 @@ snd_seq_oss_synth_init(void) * registration of the synth device */ int -snd_seq_oss_synth_register(struct snd_seq_device *dev) +snd_seq_oss_synth_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); int i; struct seq_oss_synth *rec; struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); @@ -149,8 +150,9 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev) int -snd_seq_oss_synth_unregister(struct snd_seq_device *dev) +snd_seq_oss_synth_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); int index; struct seq_oss_synth *rec = dev->driver_data; unsigned long flags; diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h index dbdfcbb80eaa..74ac55f166b6 100644 --- a/sound/core/seq/oss/seq_oss_synth.h +++ b/sound/core/seq/oss/seq_oss_synth.h @@ -28,8 +28,8 @@ #include void snd_seq_oss_synth_init(void); -int snd_seq_oss_synth_register(struct snd_seq_device *dev); -int snd_seq_oss_synth_unregister(struct snd_seq_device *dev); +int snd_seq_oss_synth_probe(struct device *dev); +int snd_seq_oss_synth_remove(struct device *dev); void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 49daf6e3a387..48b20f009598 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -52,16 +52,6 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("ALSA sequencer device management"); MODULE_LICENSE("GPL"); -struct snd_seq_driver { - struct device_driver driver; - const char *id; - int argsize; - struct snd_seq_dev_ops ops; -}; - -#define to_seq_drv(_drv) \ - container_of(_drv, struct snd_seq_driver, driver) - /* * bus definition */ @@ -263,86 +253,23 @@ int snd_seq_device_new(struct snd_card *card, int device, const char *id, EXPORT_SYMBOL(snd_seq_device_new); /* - * driver binding - just pass to each driver callback + * driver registration */ -static int snd_seq_drv_probe(struct device *dev) +int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod) { - struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); - struct snd_seq_device *sdev = to_seq_dev(dev); - - return sdrv->ops.init_device(sdev); -} - -static int snd_seq_drv_remove(struct device *dev) -{ - struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); - struct snd_seq_device *sdev = to_seq_dev(dev); - - return sdrv->ops.free_device(sdev); -} - -/* - * register device driver - * id = driver id - * entry = driver operators - duplicated to each instance - */ -int snd_seq_device_register_driver(const char *id, - struct snd_seq_dev_ops *entry, int argsize) -{ - struct snd_seq_driver *sdrv; - int err; - - if (id == NULL || entry == NULL || - entry->init_device == NULL || entry->free_device == NULL) + if (WARN_ON(!drv->driver.name || !drv->id)) return -EINVAL; - - sdrv = kzalloc(sizeof(*sdrv), GFP_KERNEL); - if (!sdrv) - return -ENOMEM; - - sdrv->driver.name = id; - sdrv->driver.bus = &snd_seq_bus_type; - sdrv->driver.probe = snd_seq_drv_probe; - sdrv->driver.remove = snd_seq_drv_remove; - sdrv->id = id; - sdrv->argsize = argsize; - sdrv->ops = *entry; - - err = driver_register(&sdrv->driver); - if (err < 0) - kfree(sdrv); - return err; -} -EXPORT_SYMBOL(snd_seq_device_register_driver); - -/* callback to find a specific driver; data is a pointer to the id string ptr. - * when the id matches, store the driver pointer in return and break the loop. - */ -static int find_drv(struct device_driver *drv, void *data) -{ - struct snd_seq_driver *sdrv = to_seq_drv(drv); - void **ptr = (void **)data; - - if (strcmp(sdrv->id, *ptr)) - return 0; /* id don't match, continue the loop */ - *ptr = sdrv; - return 1; /* break the loop */ + drv->driver.bus = &snd_seq_bus_type; + drv->driver.owner = mod; + return driver_register(&drv->driver); } +EXPORT_SYMBOL_GPL(__snd_seq_driver_register); -/* - * unregister the specified driver - */ -int snd_seq_device_unregister_driver(const char *id) +void snd_seq_driver_unregister(struct snd_seq_driver *drv) { - struct snd_seq_driver *sdrv = (struct snd_seq_driver *)id; - - if (!bus_for_each_drv(&snd_seq_bus_type, NULL, &sdrv, find_drv)) - return -ENXIO; - driver_unregister(&sdrv->driver); - kfree(sdrv); - return 0; + driver_unregister(&drv->driver); } -EXPORT_SYMBOL(snd_seq_device_unregister_driver); +EXPORT_SYMBOL_GPL(snd_seq_driver_unregister); /* * module part diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 68fec776da26..79c73119cedc 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -273,8 +273,9 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth) /* register new midi synth port */ static int -snd_seq_midisynth_register_port(struct snd_seq_device *dev) +snd_seq_midisynth_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct seq_midisynth_client *client; struct seq_midisynth *msynth, *ms; struct snd_seq_port_info *port; @@ -427,8 +428,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) /* release midi synth port */ static int -snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) +snd_seq_midisynth_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct seq_midisynth_client *client; struct seq_midisynth *msynth; struct snd_card *card = dev->card; @@ -457,23 +459,29 @@ snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) return 0; } +static struct snd_seq_driver seq_midisynth_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_seq_midisynth_probe, + .remove = snd_seq_midisynth_remove, + }, + .id = SNDRV_SEQ_DEV_ID_MIDISYNTH, + .argsize = 0, +}; static int __init alsa_seq_midi_init(void) { - static struct snd_seq_dev_ops ops = { - snd_seq_midisynth_register_port, - snd_seq_midisynth_unregister_port, - }; - memset(&synths, 0, sizeof(synths)); + int err; + snd_seq_autoload_lock(); - snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0); + err = snd_seq_driver_register(&seq_midisynth_driver); snd_seq_autoload_unlock(); - return 0; + return err; } static void __exit alsa_seq_midi_exit(void) { - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH); + snd_seq_driver_unregister(&seq_midisynth_driver); } module_init(alsa_seq_midi_init) diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index a9f618e06a22..fdae5d7f421f 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -216,8 +216,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3) /* ------------------------------ */ -static int snd_opl3_seq_new_device(struct snd_seq_device *dev) +static int snd_opl3_seq_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl3 *opl3; int client, err; char name[32]; @@ -257,8 +258,9 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev) return 0; } -static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) +static int snd_opl3_seq_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl3 *opl3; opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); @@ -275,22 +277,14 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) return 0; } -static int __init alsa_opl3_seq_init(void) -{ - static struct snd_seq_dev_ops ops = - { - snd_opl3_seq_new_device, - snd_opl3_seq_delete_device - }; - - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops, - sizeof(struct snd_opl3 *)); -} - -static void __exit alsa_opl3_seq_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3); -} +static struct snd_seq_driver opl3_seq_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_opl3_seq_probe, + .remove = snd_opl3_seq_remove, + }, + .id = SNDRV_SEQ_DEV_ID_OPL3, + .argsize = sizeof(struct snd_opl3 *), +}; -module_init(alsa_opl3_seq_init) -module_exit(alsa_opl3_seq_exit) +module_snd_seq_driver(opl3_seq_driver); diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c index 99197699c55a..03d6202f4829 100644 --- a/sound/drivers/opl4/opl4_seq.c +++ b/sound/drivers/opl4/opl4_seq.c @@ -124,8 +124,9 @@ static void snd_opl4_seq_free_port(void *private_data) snd_midi_channel_free_set(opl4->chset); } -static int snd_opl4_seq_new_device(struct snd_seq_device *dev) +static int snd_opl4_seq_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl4 *opl4; int client; struct snd_seq_port_callback pcallbacks; @@ -180,8 +181,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev) return 0; } -static int snd_opl4_seq_delete_device(struct snd_seq_device *dev) +static int snd_opl4_seq_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl4 *opl4; opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); @@ -195,21 +197,14 @@ static int snd_opl4_seq_delete_device(struct snd_seq_device *dev) return 0; } -static int __init alsa_opl4_synth_init(void) -{ - static struct snd_seq_dev_ops ops = { - snd_opl4_seq_new_device, - snd_opl4_seq_delete_device - }; - - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops, - sizeof(struct snd_opl4 *)); -} - -static void __exit alsa_opl4_synth_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4); -} +static struct snd_seq_driver opl4_seq_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_opl4_seq_probe, + .remove = snd_opl4_seq_remove, + }, + .id = SNDRV_SEQ_DEV_ID_OPL4, + .argsize = sizeof(struct snd_opl4 *), +}; -module_init(alsa_opl4_synth_init) -module_exit(alsa_opl4_synth_exit) +module_snd_seq_driver(opl4_seq_driver); diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c index 72332dfada9a..4aa719cad331 100644 --- a/sound/isa/sb/emu8000_synth.c +++ b/sound/isa/sb/emu8000_synth.c @@ -34,8 +34,9 @@ MODULE_LICENSE("GPL"); /* * create a new hardware dependent device for Emu8000 */ -static int snd_emu8000_new_device(struct snd_seq_device *dev) +static int snd_emu8000_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emu8000 *hw; struct snd_emux *emu; @@ -93,8 +94,9 @@ static int snd_emu8000_new_device(struct snd_seq_device *dev) /* * free all resources */ -static int snd_emu8000_delete_device(struct snd_seq_device *dev) +static int snd_emu8000_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emu8000 *hw; if (dev->driver_data == NULL) @@ -114,21 +116,14 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev) * INIT part */ -static int __init alsa_emu8000_init(void) -{ - - static struct snd_seq_dev_ops ops = { - snd_emu8000_new_device, - snd_emu8000_delete_device, - }; - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU8000, &ops, - sizeof(struct snd_emu8000*)); -} - -static void __exit alsa_emu8000_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000); -} - -module_init(alsa_emu8000_init) -module_exit(alsa_emu8000_exit) +static struct snd_seq_driver emu8000_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_emu8000_probe, + .remove = snd_emu8000_remove, + }, + .id = SNDRV_SEQ_DEV_ID_EMU8000, + .argsize = sizeof(struct snd_emu8000 *), +}; + +module_snd_seq_driver(emu8000_driver); diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 4c41c903a840..5457d5613f6b 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c @@ -29,8 +29,9 @@ MODULE_LICENSE("GPL"); /* * create a new hardware dependent device for Emu10k1 */ -static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) +static int snd_emu10k1_synth_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emux *emux; struct snd_emu10k1 *hw; struct snd_emu10k1_synth_arg *arg; @@ -79,8 +80,9 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) return 0; } -static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) +static int snd_emu10k1_synth_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emux *emux; struct snd_emu10k1 *hw; unsigned long flags; @@ -104,21 +106,14 @@ static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) * INIT part */ -static int __init alsa_emu10k1_synth_init(void) -{ - - static struct snd_seq_dev_ops ops = { - snd_emu10k1_synth_new_device, - snd_emu10k1_synth_delete_device, - }; - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, &ops, - sizeof(struct snd_emu10k1_synth_arg)); -} - -static void __exit alsa_emu10k1_synth_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH); -} - -module_init(alsa_emu10k1_synth_init) -module_exit(alsa_emu10k1_synth_exit) +static struct snd_seq_driver emu10k1_synth_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_emu10k1_synth_probe, + .remove = snd_emu10k1_synth_remove, + }, + .id = SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, + .argsize = sizeof(struct snd_emu10k1_synth_arg), +}; + +module_snd_seq_driver(emu10k1_synth_driver); -- cgit v1.2.3 From 54a721abd7953a58e5479065c0cfdd8679d785c9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 14:20:24 +0100 Subject: ALSA: seq: Drop snd_seq_autoload_lock() and _unlock() The autoload lock became already superfluous due to the recent rework of autoload code. Let's drop them now. This allows us to simplify a few codes nicely. Signed-off-by: Takashi Iwai --- include/sound/seq_kernel.h | 6 +----- sound/core/seq/oss/seq_oss.c | 2 -- sound/core/seq/seq_device.c | 19 +++++++------------ sound/core/seq/seq_dummy.c | 6 +----- sound/core/seq/seq_midi.c | 18 +----------------- 5 files changed, 10 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h index 18a2ac58b88f..feb58d455560 100644 --- a/include/sound/seq_kernel.h +++ b/include/sound/seq_kernel.h @@ -99,13 +99,9 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp, int snd_seq_event_port_detach(int client, int port); #ifdef CONFIG_MODULES -void snd_seq_autoload_lock(void); -void snd_seq_autoload_unlock(void); void snd_seq_autoload_init(void); -#define snd_seq_autoload_exit() snd_seq_autoload_lock() +void snd_seq_autoload_exit(void); #else -#define snd_seq_autoload_lock() -#define snd_seq_autoload_unlock() #define snd_seq_autoload_init() #define snd_seq_autoload_exit() #endif diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index ae1814aa767e..72873a46afeb 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -79,7 +79,6 @@ static int __init alsa_seq_oss_init(void) { int rc; - snd_seq_autoload_lock(); if ((rc = register_device()) < 0) goto error; if ((rc = register_proc()) < 0) { @@ -104,7 +103,6 @@ static int __init alsa_seq_oss_init(void) snd_seq_oss_synth_init(); error: - snd_seq_autoload_unlock(); return rc; } diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 48b20f009598..355b34269bd1 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -98,19 +98,8 @@ static void snd_seq_device_info(struct snd_info_entry *entry, */ #ifdef CONFIG_MODULES -/* avoid auto-loading during module_init() */ +/* flag to block auto-loading */ static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */ -void snd_seq_autoload_lock(void) -{ - atomic_inc(&snd_seq_in_init); -} -EXPORT_SYMBOL(snd_seq_autoload_lock); - -void snd_seq_autoload_unlock(void) -{ - atomic_dec(&snd_seq_in_init); -} -EXPORT_SYMBOL(snd_seq_autoload_unlock); static int request_seq_drv(struct device *dev, void *data) { @@ -147,6 +136,12 @@ void snd_seq_autoload_init(void) } EXPORT_SYMBOL(snd_seq_autoload_init); +void snd_seq_autoload_exit(void) +{ + atomic_inc(&snd_seq_in_init); +} +EXPORT_SYMBOL(snd_seq_autoload_exit); + void snd_seq_device_load_drivers(void) { queue_autoload_drivers(); diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index 5d905d90d504..d3a2ec4f0561 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -214,11 +214,7 @@ delete_client(void) static int __init alsa_seq_dummy_init(void) { - int err; - snd_seq_autoload_lock(); - err = register_client(); - snd_seq_autoload_unlock(); - return err; + return register_client(); } static void __exit alsa_seq_dummy_exit(void) diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 79c73119cedc..5dd0ee258359 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -469,20 +469,4 @@ static struct snd_seq_driver seq_midisynth_driver = { .argsize = 0, }; -static int __init alsa_seq_midi_init(void) -{ - int err; - - snd_seq_autoload_lock(); - err = snd_seq_driver_register(&seq_midisynth_driver); - snd_seq_autoload_unlock(); - return err; -} - -static void __exit alsa_seq_midi_exit(void) -{ - snd_seq_driver_unregister(&seq_midisynth_driver); -} - -module_init(alsa_seq_midi_init) -module_exit(alsa_seq_midi_exit) +module_snd_seq_driver(seq_midisynth_driver); -- cgit v1.2.3 From bf2b8a515530ee7e3b25214d7ec52c6827f12d70 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 29 Jan 2015 14:13:38 +0000 Subject: drm/i915/skl: Split the SKL PCI ids by GT We need to have a separate GT3 struct intel_device_info to declare they have a second VCS. Let's start by splitting the PCI ids per-GT. Signed-off-by: Damien Lespiau Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- include/drm/i915_pciids.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 180ad0e6de21..38a7c8049e47 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -259,21 +259,31 @@ INTEL_VGA_DEVICE(0x22b2, info), \ INTEL_VGA_DEVICE(0x22b3, info) -#define INTEL_SKL_IDS(info) \ - INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \ +#define INTEL_SKL_GT1_IDS(info) \ INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \ - INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \ - INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \ INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \ + INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \ + INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \ + INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */ + +#define INTEL_SKL_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \ + INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \ INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \ INTEL_VGA_DEVICE(0x1912, info), /* DT GT2 */ \ - INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \ INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \ - INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \ - INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \ INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \ - INTEL_VGA_DEVICE(0x192A, info), /* SRV GT3 */ \ - INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ \ INTEL_VGA_DEVICE(0x191D, info) /* WKS GT2 */ +#define INTEL_SKL_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \ + INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ \ + +#define INTEL_SKL_IDS(info) \ + INTEL_SKL_GT1_IDS(info), \ + INTEL_SKL_GT2_IDS(info), \ + INTEL_SKL_GT3_IDS(info) + + #endif /* _I915_PCIIDS_H */ -- cgit v1.2.3 From e3eb3250d84ef97b766312345774367b6a310db8 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 5 Feb 2015 14:41:52 +0000 Subject: drm: add support for tiled/compressed/etc modifier in addfb2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In DRM/KMS we are lacking a good way to deal with tiled/compressed formats. Especially in the case of dmabuf/prime buffer sharing, where we cannot always rely on under-the-hood flags passed to driver specific gem-create ioctl to pass around these extra flags. The proposal is to add a per-plane format modifier. This allows to, if necessary, use different tiling patters for sub-sampled planes, etc. The format modifiers are added at the end of the ioctl struct, so for legacy userspace it will be zero padded. v1: original v1.5: increase modifier to 64b v2: Incorporate review comments from the big thread, plus a few more. - Add a getcap so that userspace doesn't have to jump through hoops. - Allow modifiers only when a flag is set. That way drivers know when they're dealing with old userspace and need to fish out e.g. tiling from other information. - After rolling out checks for ->modifier to all drivers I've decided that this is way too fragile and needs an explicit opt-in flag. So do that instead. - Add a define (just for documentation really) for the "NONE" modifier. Imo we don't need to add mask #defines since drivers really should only do exact matches against values defined with fourcc_mod_code. - Drop the Samsung tiling modifier on Rob's request since he's not yet sure whether that one is accurate. v3: - Also add a new ->modifier[] array to struct drm_framebuffer and fill it in drm_helper_mode_fill_fb_struct. Requested by Tvrkto Uruslin. - Remove TODO in comment and add code comment that modifiers should be properly documented, requested by Rob. Cc: Rob Clark Cc: Tvrtko Ursulin Cc: Laurent Pinchart Cc: Daniel Stone Cc: Ville Syrjälä Cc: Michel Dänzer Signed-off-by: Rob Clark (v1.5) Reviewed-by: Rob Clark Reviewed-by: Daniel Stone Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 14 +++++++++++++- drivers/gpu/drm/drm_crtc_helper.c | 1 + drivers/gpu/drm/drm_ioctl.c | 3 +++ include/drm/drm_crtc.h | 4 ++++ include/uapi/drm/drm.h | 1 + include/uapi/drm/drm_fourcc.h | 32 ++++++++++++++++++++++++++++++++ include/uapi/drm/drm_mode.h | 9 +++++++++ 7 files changed, 63 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index ad2934ba0bd2..b15d720eda4c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3314,6 +3314,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); return -EINVAL; } + + if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { + DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", + r->modifier[i], i); + return -EINVAL; + } } return 0; @@ -3327,7 +3333,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, struct drm_framebuffer *fb; int ret; - if (r->flags & ~DRM_MODE_FB_INTERLACED) { + if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); return ERR_PTR(-EINVAL); } @@ -3343,6 +3349,12 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, return ERR_PTR(-EINVAL); } + if (r->flags & DRM_MODE_FB_MODIFIERS && + !dev->mode_config.allow_fb_modifiers) { + DRM_DEBUG_KMS("driver does not support fb modifiers\n"); + return ERR_PTR(-EINVAL); + } + ret = framebuffer_check(r); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index b1979e7bdc88..3053aab968f9 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -837,6 +837,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, for (i = 0; i < 4; i++) { fb->pitches[i] = mode_cmd->pitches[i]; fb->offsets[i] = mode_cmd->offsets[i]; + fb->modifier[i] = mode_cmd->modifier[i]; } drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, &fb->bits_per_pixel); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 3785d66721f2..a6d773a61c2d 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ else req->value = 64; break; + case DRM_CAP_ADDFB2_MODIFIERS: + req->value = dev->mode_config.allow_fb_modifiers; + break; default: return -EINVAL; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0ebd9286b332..cee54c45eba9 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -202,6 +202,7 @@ struct drm_framebuffer { const struct drm_framebuffer_funcs *funcs; unsigned int pitches[4]; unsigned int offsets[4]; + uint64_t modifier[4]; unsigned int width; unsigned int height; /* depth can be 15 or 16 */ @@ -1152,6 +1153,9 @@ struct drm_mode_config { /* whether async page flip is supported or not */ bool async_page_flip; + /* whether the driver supports fb modifiers */ + bool allow_fb_modifiers; + /* cursor size */ uint32_t cursor_width, cursor_height; }; diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 01b2d6d0e355..ff6ef62d084b 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -630,6 +630,7 @@ struct drm_gem_open { */ #define DRM_CAP_CURSOR_WIDTH 0x8 #define DRM_CAP_CURSOR_HEIGHT 0x9 +#define DRM_CAP_ADDFB2_MODIFIERS 0x10 /** DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 646ae5f39f42..622109677747 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -132,4 +132,36 @@ #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ + +/* + * Format Modifiers: + * + * Format modifiers describe, typically, a re-ordering or modification + * of the data in a plane of an FB. This can be used to express tiled/ + * swizzled formats, or compression, or a combination of the two. + * + * The upper 8 bits of the format modifier are a vendor-id as assigned + * below. The lower 56 bits are assigned as vendor sees fit. + */ + +/* Vendor Ids: */ +#define DRM_FORMAT_MOD_NONE 0 +#define DRM_FORMAT_MOD_VENDOR_INTEL 0x01 +#define DRM_FORMAT_MOD_VENDOR_AMD 0x02 +#define DRM_FORMAT_MOD_VENDOR_NV 0x03 +#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04 +#define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 +/* add more to the end as needed */ + +#define fourcc_mod_code(vendor, val) \ + ((((u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffL)) + +/* + * Format Modifier tokens: + * + * When adding a new token please document the layout with a code comment, + * similar to the fourcc codes above. drm_fourcc.h is considered the + * authoritative source for all of these. + */ + #endif /* DRM_FOURCC_H */ diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index ca788e01dab2..dbeba949462a 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -336,6 +336,7 @@ struct drm_mode_fb_cmd { }; #define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */ +#define DRM_MODE_FB_MODIFIERS (1<<1) /* enables ->modifer[] */ struct drm_mode_fb_cmd2 { __u32 fb_id; @@ -356,10 +357,18 @@ struct drm_mode_fb_cmd2 { * So it would consist of Y as offsets[0] and UV as * offsets[1]. Note that offsets[0] will generally * be 0 (but this is not required). + * + * To accommodate tiled, compressed, etc formats, a per-plane + * modifier can be specified. The default value of zero + * indicates "native" format as specified by the fourcc. + * Vendor specific modifier token. This allows, for example, + * different tiling/swizzling pattern on different planes. + * See discussion above of DRM_FORMAT_MOD_xxx. */ __u32 handles[4]; __u32 pitches[4]; /* pitch for each plane */ __u32 offsets[4]; /* offset of each plane */ + __u64 modifier[4]; /* ie, tiling, compressed (per plane) */ }; #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 -- cgit v1.2.3 From 93b81f5102a7cd270a305c2741b17c8d44bb0629 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 10 Feb 2015 17:16:05 +0000 Subject: drm/i915: Add tiled framebuffer modifiers To be used from the new addfb2 extension. v2: - Drop Intel-specific untiled modfier. - Move to drm_fourcc.h. - Document layouts a bit and denote them as platform-specific and not useable for cross-driver sharing. - Add Y-tiling for completeness. - Drop special docstring markers to avoid confusing kerneldoc. v3: Give Y-tiling a unique idea, noticed by Tvrtko. Signed-off-by: Tvrtko Ursulin (v1) Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + include/uapi/drm/drm_fourcc.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3da3dc527315..99b25928df2f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -31,6 +31,7 @@ #define _I915_DRV_H_ #include +#include #include "i915_reg.h" #include "intel_bios.h" diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 622109677747..4837c3d2319a 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -164,4 +164,35 @@ * authoritative source for all of these. */ +/* Intel framebuffer modifiers */ + +/* + * Intel X-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out row-major, with + * a platform-dependent stride. On top of that the memory can apply + * platform-depending swizzling of some higher address bits into bit6. + * + * This format is highly platforms specific and not useful for cross-driver + * sharing. It exists since on a given platform it does uniquely identify the + * layout in a simple way for i915-specific userspace. + */ +#define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1) + +/* + * Intel Y-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes) + * chunks column-major, with a platform-dependent height. On top of that the + * memory can apply platform-depending swizzling of some higher address bits + * into bit6. + * + * This format is highly platforms specific and not useful for cross-driver + * sharing. It exists since on a given platform it does uniquely identify the + * layout in a simple way for i915-specific userspace. + */ +#define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) + #endif /* DRM_FOURCC_H */ -- cgit v1.2.3 From e31a0ba7df6ce21ac4ed58c4182ec12ca8fd78fb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 2 Jan 2015 12:18:23 -0300 Subject: [media] media: Fix DVB devnode representation at media controller The previous provision for DVB media controller support were to define an ID (likely meaning the adapter number) for the DVB devnodes. This is just plain wrong. Just like V4L, DVB devices (and any other device node)) are uniquely identified via a (major, minor) tuple. This is enough to uniquely identify a devnode, no matter what API it implements. So, before we go too far, let's mark the old v4l, fb, dvb and alsa "devnode" info as deprecated, and just call it as "dev". We can latter add fields specific to each API if needed. As we don't want to break compilation on already existing apps, let's just keep the old definitions as-is, adding a note that those are deprecated at media-entity.h. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 4 ++-- drivers/media/v4l2-core/v4l2-device.c | 4 ++-- include/media/media-entity.h | 12 +----------- include/uapi/linux/media.h | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 86bb93fd7db8..d89d5cb465d9 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -943,8 +943,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; - vdev->entity.info.v4l.major = VIDEO_MAJOR; - vdev->entity.info.v4l.minor = vdev->minor; + vdev->entity.info.dev.major = VIDEO_MAJOR; + vdev->entity.info.dev.minor = vdev->minor; ret = media_device_register_entity(vdev->v4l2_dev->mdev, &vdev->entity); if (ret < 0) diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 015f92aab44a..204cc67c84e8 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -248,8 +248,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) goto clean_up; } #if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.info.v4l.major = VIDEO_MAJOR; - sd->entity.info.v4l.minor = vdev->minor; + sd->entity.info.dev.major = VIDEO_MAJOR; + sd->entity.info.dev.minor = vdev->minor; #endif sd->devnode = vdev; } diff --git a/include/media/media-entity.h b/include/media/media-entity.h index e00459185d20..d6d74bcfe183 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -87,17 +87,7 @@ struct media_entity { struct { u32 major; u32 minor; - } v4l; - struct { - u32 major; - u32 minor; - } fb; - struct { - u32 card; - u32 device; - u32 subdevice; - } alsa; - int dvb; + } dev; /* Sub-device specifications */ /* Nothing needed yet */ diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index d847c760e8f0..418f4fec391a 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -75,6 +75,20 @@ struct media_entity_desc { union { /* Node specifications */ + struct { + __u32 major; + __u32 minor; + } dev; + +#if 1 + /* + * DEPRECATED: previous node specifications. Kept just to + * avoid breaking compilation, but media_entity_desc.dev + * should be used instead. In particular, alsa and dvb + * fields below are wrong: for all devnodes, there should + * be just major/minor inside the struct, as this is enough + * to represent any devnode, no matter what type. + */ struct { __u32 major; __u32 minor; @@ -89,6 +103,7 @@ struct media_entity_desc { __u32 subdevice; } alsa; int dvb; +#endif /* Sub-device specifications */ /* Nothing needed yet */ -- cgit v1.2.3 From 1d20f9f6330c988505e51f5010656978fd70cd0c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Jan 2015 11:09:39 -0300 Subject: [media] media: add new types for DVB devnodes Most of the DVB subdevs have already their own devnode. Add support for them at the media controller API. Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/media.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 418f4fec391a..4c8f26243252 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -50,7 +50,14 @@ struct media_device_info { #define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1) #define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2) #define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) -#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) +#define MEDIA_ENT_T_DEVNODE_DVB_FE (MEDIA_ENT_T_DEVNODE + 4) +#define MEDIA_ENT_T_DEVNODE_DVB_DEMUX (MEDIA_ENT_T_DEVNODE + 5) +#define MEDIA_ENT_T_DEVNODE_DVB_DVR (MEDIA_ENT_T_DEVNODE + 6) +#define MEDIA_ENT_T_DEVNODE_DVB_CA (MEDIA_ENT_T_DEVNODE + 7) +#define MEDIA_ENT_T_DEVNODE_DVB_NET (MEDIA_ENT_T_DEVNODE + 8) + +/* Legacy symbol. Use it to avoid userspace compilation breakages */ +#define MEDIA_ENT_T_DEVNODE_DVB MEDIA_ENT_T_DEVNODE_DVB_FE #define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT) #define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1) -- cgit v1.2.3 From 91b0f3a06e432d01c66cd05973628a2ec3bde9ed Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Jan 2015 08:53:18 -0300 Subject: [media] media: add a subdev type for tuner Add MEDIA_ENT_T_V4L2_SUBDEV_TUNER to represent the V4L2 (and dvb) tuner subdevices. Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/media.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 4c8f26243252..52cc2a6b19b7 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -66,6 +66,8 @@ struct media_device_info { /* A converter of analogue video to its digital representation. */ #define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4) +#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER (MEDIA_ENT_T_V4L2_SUBDEV + 5) + #define MEDIA_ENT_FL_DEFAULT (1 << 0) struct media_entity_desc { -- cgit v1.2.3 From 306f7aa1807be7588f115d7cafa475f65e72e3d1 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 11 Feb 2015 14:39:15 +0100 Subject: ieee802154: correct ieee802154_is_valid_psdu_len This patch corrects the ieee802154_is_valid_psdu_len function that this function also checks on reserved values 6-8 for validation the psdu length. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/linux/ieee802154.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index 6e82d888287c..40b0ab953937 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -28,7 +28,8 @@ #include #define IEEE802154_MTU 127 -#define IEEE802154_MIN_PSDU_LEN 5 +#define IEEE802154_ACK_PSDU_LEN 5 +#define IEEE802154_MIN_PSDU_LEN 9 #define IEEE802154_PAN_ID_BROADCAST 0xffff #define IEEE802154_ADDR_SHORT_BROADCAST 0xffff @@ -204,11 +205,18 @@ enum { /** * ieee802154_is_valid_psdu_len - check if psdu len is valid + * available lengths: + * 0-4 Reserved + * 5 MPDU (Acknowledgment) + * 6-8 Reserved + * 9-127 MPDU + * * @len: psdu len with (MHR + payload + MFR) */ static inline bool ieee802154_is_valid_psdu_len(const u8 len) { - return (len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU); + return (len == IEEE802154_ACK_PSDU_LEN || + (len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU)); } /** -- cgit v1.2.3 From ba5bf17e8343c0b5b87a1240aa75c35c76b88e5e Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 11 Feb 2015 14:39:16 +0100 Subject: ieee802154: cleanup ieee802154_be64_to_le64 This patch cleanups the ieee802154_be64_to_le64 function. This patch removes an unnecessary temporary variable. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 850647811749..c5c64455bcfa 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -233,9 +234,7 @@ struct ieee802154_ops { */ static inline void ieee802154_be64_to_le64(void *le64_dst, const void *be64_src) { - __le64 tmp = (__force __le64)swab64p(be64_src); - - memcpy(le64_dst, &tmp, IEEE802154_EXTENDED_ADDR_LEN); + __put_unaligned_memmove64(swab64p(be64_src), le64_dst); } /** -- cgit v1.2.3 From b976796950c7a41fe1b6b51236ddd08dd6480b80 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 11 Feb 2015 14:39:17 +0100 Subject: ieee802154: cleanup ieee802154_le64_to_be64 This patch cleanups the ieee802154_le64_to_be64 function. This patch removes an unnecessary temporary variable. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index c5c64455bcfa..fb4e8a3d6229 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -244,9 +244,7 @@ static inline void ieee802154_be64_to_le64(void *le64_dst, const void *be64_src) */ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src) { - __be64 tmp = (__force __be64)swab64p(le64_src); - - memcpy(be64_dst, &tmp, IEEE802154_EXTENDED_ADDR_LEN); + __put_unaligned_memmove64(swab64p(le64_src), be64_dst); } /* Basic interface to register ieee802154 hwice */ -- cgit v1.2.3 From 293487c8ecc1103f4625cea5e90e1ba0cc89660f Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 10 Feb 2015 18:33:51 +0200 Subject: iio: Export userspace IIO headers After UAPI header file split [1] all user-kernel interfaces were placed under include/uapi/. This patch moves IIO user specific API from: * include/linux/iio/events.h => include/uapi/linux/iio/events.h * include/linux/types.h => include/uapi/linux/types.h Now there is no need for nasty tricks to compile userspace programs (e.g iio_event_monitor). Just installing the kernel headers with make headers_install command does the job. [1] http://lwn.net/Articles/507794/ Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- include/linux/iio/events.h | 30 +------------- include/linux/iio/types.h | 78 +--------------------------------- include/uapi/linux/Kbuild | 1 + include/uapi/linux/iio/Kbuild | 3 ++ include/uapi/linux/iio/events.h | 42 +++++++++++++++++++ include/uapi/linux/iio/types.h | 92 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 106 deletions(-) create mode 100644 include/uapi/linux/iio/Kbuild create mode 100644 include/uapi/linux/iio/events.h create mode 100644 include/uapi/linux/iio/types.h (limited to 'include') diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h index 03fa332ad2a8..8ad87d1c5340 100644 --- a/include/linux/iio/events.h +++ b/include/linux/iio/events.h @@ -9,22 +9,8 @@ #ifndef _IIO_EVENTS_H_ #define _IIO_EVENTS_H_ -#include -#include #include - -/** - * struct iio_event_data - The actual event being pushed to userspace - * @id: event identifier - * @timestamp: best estimate of time of event occurrence (often from - * the interrupt handler) - */ -struct iio_event_data { - __u64 id; - __s64 timestamp; -}; - -#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int) +#include /** * IIO_EVENT_CODE() - create event identifier @@ -70,18 +56,4 @@ struct iio_event_data { #define IIO_UNMOD_EVENT_CODE(chan_type, number, type, direction) \ IIO_EVENT_CODE(chan_type, 0, 0, direction, type, number, 0, 0) -#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF) - -#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0x7F) - -#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF) - -/* Event code number extraction depends on which type of event we have. - * Perhaps review this function in the future*/ -#define IIO_EVENT_CODE_EXTRACT_CHAN(mask) ((__s16)(mask & 0xFFFF)) -#define IIO_EVENT_CODE_EXTRACT_CHAN2(mask) ((__s16)(((mask) >> 16) & 0xFFFF)) - -#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF) -#define IIO_EVENT_CODE_EXTRACT_DIFF(mask) (((mask) >> 55) & 0x1) - #endif diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 580ed5bdb3fa..942b6de68e2f 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -10,76 +10,7 @@ #ifndef _IIO_TYPES_H_ #define _IIO_TYPES_H_ -enum iio_chan_type { - IIO_VOLTAGE, - IIO_CURRENT, - IIO_POWER, - IIO_ACCEL, - IIO_ANGL_VEL, - IIO_MAGN, - IIO_LIGHT, - IIO_INTENSITY, - IIO_PROXIMITY, - IIO_TEMP, - IIO_INCLI, - IIO_ROT, - IIO_ANGL, - IIO_TIMESTAMP, - IIO_CAPACITANCE, - IIO_ALTVOLTAGE, - IIO_CCT, - IIO_PRESSURE, - IIO_HUMIDITYRELATIVE, - IIO_ACTIVITY, - IIO_STEPS, - IIO_ENERGY, - IIO_DISTANCE, - IIO_VELOCITY, -}; - -enum iio_modifier { - IIO_NO_MOD, - IIO_MOD_X, - IIO_MOD_Y, - IIO_MOD_Z, - IIO_MOD_X_AND_Y, - IIO_MOD_X_AND_Z, - IIO_MOD_Y_AND_Z, - IIO_MOD_X_AND_Y_AND_Z, - IIO_MOD_X_OR_Y, - IIO_MOD_X_OR_Z, - IIO_MOD_Y_OR_Z, - IIO_MOD_X_OR_Y_OR_Z, - IIO_MOD_LIGHT_BOTH, - IIO_MOD_LIGHT_IR, - IIO_MOD_ROOT_SUM_SQUARED_X_Y, - IIO_MOD_SUM_SQUARED_X_Y_Z, - IIO_MOD_LIGHT_CLEAR, - IIO_MOD_LIGHT_RED, - IIO_MOD_LIGHT_GREEN, - IIO_MOD_LIGHT_BLUE, - IIO_MOD_QUATERNION, - IIO_MOD_TEMP_AMBIENT, - IIO_MOD_TEMP_OBJECT, - IIO_MOD_NORTH_MAGN, - IIO_MOD_NORTH_TRUE, - IIO_MOD_NORTH_MAGN_TILT_COMP, - IIO_MOD_NORTH_TRUE_TILT_COMP, - IIO_MOD_RUNNING, - IIO_MOD_JOGGING, - IIO_MOD_WALKING, - IIO_MOD_STILL, - IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z, -}; - -enum iio_event_type { - IIO_EV_TYPE_THRESH, - IIO_EV_TYPE_MAG, - IIO_EV_TYPE_ROC, - IIO_EV_TYPE_THRESH_ADAPTIVE, - IIO_EV_TYPE_MAG_ADAPTIVE, - IIO_EV_TYPE_CHANGE, -}; +#include enum iio_event_info { IIO_EV_INFO_ENABLE, @@ -88,13 +19,6 @@ enum iio_event_info { IIO_EV_INFO_PERIOD, }; -enum iio_event_direction { - IIO_EV_DIR_EITHER, - IIO_EV_DIR_RISING, - IIO_EV_DIR_FALLING, - IIO_EV_DIR_NONE, -}; - #define IIO_VAL_INT 1 #define IIO_VAL_INT_PLUS_MICRO 2 #define IIO_VAL_INT_PLUS_NANO 3 diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 00b100023c47..5bfc5bdc3c5d 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -6,6 +6,7 @@ header-y += caif/ header-y += dvb/ header-y += hdlc/ header-y += hsi/ +header-y += iio/ header-y += isdn/ header-y += mmc/ header-y += nfsd/ diff --git a/include/uapi/linux/iio/Kbuild b/include/uapi/linux/iio/Kbuild new file mode 100644 index 000000000000..86f76d84c44f --- /dev/null +++ b/include/uapi/linux/iio/Kbuild @@ -0,0 +1,3 @@ +# UAPI Header export list +header-y += events.h +header-y += types.h diff --git a/include/uapi/linux/iio/events.h b/include/uapi/linux/iio/events.h new file mode 100644 index 000000000000..00bbdaed2f97 --- /dev/null +++ b/include/uapi/linux/iio/events.h @@ -0,0 +1,42 @@ +/* The industrial I/O - event passing to userspace + * + * Copyright (c) 2008-2011 Jonathan Cameron + * + * 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 _UAPI_IIO_EVENTS_H_ +#define _UAPI_IIO_EVENTS_H_ + +#include +#include + +/** + * struct iio_event_data - The actual event being pushed to userspace + * @id: event identifier + * @timestamp: best estimate of time of event occurrence (often from + * the interrupt handler) + */ +struct iio_event_data { + __u64 id; + __s64 timestamp; +}; + +#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int) + +#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF) + +#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0x7F) + +#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF) + +/* Event code number extraction depends on which type of event we have. + * Perhaps review this function in the future*/ +#define IIO_EVENT_CODE_EXTRACT_CHAN(mask) ((__s16)(mask & 0xFFFF)) +#define IIO_EVENT_CODE_EXTRACT_CHAN2(mask) ((__s16)(((mask) >> 16) & 0xFFFF)) + +#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF) +#define IIO_EVENT_CODE_EXTRACT_DIFF(mask) (((mask) >> 55) & 0x1) + +#endif /* _UAPI_IIO_EVENTS_H_ */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h new file mode 100644 index 000000000000..5c4601935005 --- /dev/null +++ b/include/uapi/linux/iio/types.h @@ -0,0 +1,92 @@ +/* industrial I/O data types needed both in and out of kernel + * + * Copyright (c) 2008 Jonathan Cameron + * + * 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 _UAPI_IIO_TYPES_H_ +#define _UAPI_IIO_TYPES_H_ + +enum iio_chan_type { + IIO_VOLTAGE, + IIO_CURRENT, + IIO_POWER, + IIO_ACCEL, + IIO_ANGL_VEL, + IIO_MAGN, + IIO_LIGHT, + IIO_INTENSITY, + IIO_PROXIMITY, + IIO_TEMP, + IIO_INCLI, + IIO_ROT, + IIO_ANGL, + IIO_TIMESTAMP, + IIO_CAPACITANCE, + IIO_ALTVOLTAGE, + IIO_CCT, + IIO_PRESSURE, + IIO_HUMIDITYRELATIVE, + IIO_ACTIVITY, + IIO_STEPS, + IIO_ENERGY, + IIO_DISTANCE, + IIO_VELOCITY, +}; + +enum iio_modifier { + IIO_NO_MOD, + IIO_MOD_X, + IIO_MOD_Y, + IIO_MOD_Z, + IIO_MOD_X_AND_Y, + IIO_MOD_X_AND_Z, + IIO_MOD_Y_AND_Z, + IIO_MOD_X_AND_Y_AND_Z, + IIO_MOD_X_OR_Y, + IIO_MOD_X_OR_Z, + IIO_MOD_Y_OR_Z, + IIO_MOD_X_OR_Y_OR_Z, + IIO_MOD_LIGHT_BOTH, + IIO_MOD_LIGHT_IR, + IIO_MOD_ROOT_SUM_SQUARED_X_Y, + IIO_MOD_SUM_SQUARED_X_Y_Z, + IIO_MOD_LIGHT_CLEAR, + IIO_MOD_LIGHT_RED, + IIO_MOD_LIGHT_GREEN, + IIO_MOD_LIGHT_BLUE, + IIO_MOD_QUATERNION, + IIO_MOD_TEMP_AMBIENT, + IIO_MOD_TEMP_OBJECT, + IIO_MOD_NORTH_MAGN, + IIO_MOD_NORTH_TRUE, + IIO_MOD_NORTH_MAGN_TILT_COMP, + IIO_MOD_NORTH_TRUE_TILT_COMP, + IIO_MOD_RUNNING, + IIO_MOD_JOGGING, + IIO_MOD_WALKING, + IIO_MOD_STILL, + IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z, +}; + +enum iio_event_type { + IIO_EV_TYPE_THRESH, + IIO_EV_TYPE_MAG, + IIO_EV_TYPE_ROC, + IIO_EV_TYPE_THRESH_ADAPTIVE, + IIO_EV_TYPE_MAG_ADAPTIVE, + IIO_EV_TYPE_CHANGE, +}; + +enum iio_event_direction { + IIO_EV_DIR_EITHER, + IIO_EV_DIR_RISING, + IIO_EV_DIR_FALLING, + IIO_EV_DIR_NONE, +}; + +#endif /* _UAPI_IIO_TYPES_H_ */ + -- cgit v1.2.3 From a44fecbd52a4d9c36f07eb2161c153047d8765d4 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Fri, 13 Feb 2015 09:20:50 -0800 Subject: Bluetooth: Add shutdown callback before closing the device This callback allows a vendor to send the vendor specific commands before cloing the hci interface. Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 52863c3e0b13..5f1ca3359c1a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -373,6 +373,7 @@ struct hci_dev { int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); int (*setup)(struct hci_dev *hdev); + int (*shutdown)(struct hci_dev *hdev); int (*send)(struct hci_dev *hdev, struct sk_buff *skb); void (*notify)(struct hci_dev *hdev, unsigned int evt); void (*hw_error)(struct hci_dev *hdev, u8 code); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3322d3f4c85a..4135a4406aed 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1591,6 +1591,12 @@ static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); + if (!test_bit(HCI_UNREGISTER, &hdev->dev_flags)) { + /* Execute vendor specific shutdown routine */ + if (hdev->shutdown) + hdev->shutdown(hdev); + } + cancel_delayed_work(&hdev->power_off); hci_req_cancel(hdev, ENODEV); -- cgit v1.2.3 From 76a3aeac2f6c02ecf065fa9baa279dd54bf2d819 Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:27 +0100 Subject: hdspm.h: include stdint.h in userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes compilation error: sound/hdspm.h:43:2: error: unknown type name ‘uint32_t’ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/hdspm.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/hdspm.h b/include/uapi/sound/hdspm.h index b357f1a5e29c..5737332d38f2 100644 --- a/include/uapi/sound/hdspm.h +++ b/include/uapi/sound/hdspm.h @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifdef __KERNEL__ +#include +#else +#include +#endif + /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ #define HDSPM_MAX_CHANNELS 64 -- cgit v1.2.3 From 4bebf7091aa15ec60edf0dcbc654410a87ca21fe Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:38 +0100 Subject: include/uapi/sound/asound.h: include stdlib.h in userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes compiler errors like: error: field ‘trigger_tstamp’ has incomplete type error: invalid application of ‘sizeof’ to incomplete t ype ‘struct timespec’ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 1f23cd635957..1fe3f4f3d696 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -25,6 +25,9 @@ #include +#ifndef __KERNEL__ +#include +#endif /* * protocol version -- cgit v1.2.3 From bbf91c1c5bfc00c2961f15657359ee7e87de4269 Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:42 +0100 Subject: include/uapi/sound/asequencer.h: include sound/asound.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes userspace compilation error: error: unknown type name ‘snd_seq_client_type_t’ snd_seq_client_type_t type; /* client type */ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index 09c8a00ea503..5a5fa4956ebd 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -22,6 +22,7 @@ #ifndef _UAPI__SOUND_ASEQUENCER_H #define _UAPI__SOUND_ASEQUENCER_H +#include /** version of the sequencer */ #define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1) -- cgit v1.2.3 From b9956409c281931c74ba8d0a2b61a98076a58602 Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:43 +0100 Subject: include/uapi/sound/emu10k1.h: include sound/asound.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes userspace compilation errors like: error: field ‘id’ has incomplete type struct snd_ctl_elem_id id; /* full control ID definition */ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/emu10k1.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h index d1bbaf78457a..ec1535bb6aed 100644 --- a/include/uapi/sound/emu10k1.h +++ b/include/uapi/sound/emu10k1.h @@ -23,8 +23,7 @@ #define _UAPI__SOUND_EMU10K1_H #include - - +#include /* * ---- FX8010 ---- -- cgit v1.2.3 From f9d904acb3e7e9edb470cd824fe2a21bb0df86b8 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 7 Jan 2015 10:14:43 -0800 Subject: HID: hid-sensor-hub: Correct documentation During changes to the interface, some documentation field comments were missed. Added missing comments. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- include/linux/hid-sensor-hub.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 51f7ccadf923..4173a8fdad9e 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -33,6 +33,8 @@ * @units: Measurment unit for this attribute. * @unit_expo: Exponent used in the data. * @size: Size in bytes for data size. + * @logical_minimum: Logical minimum value for this attribute. + * @logical_maximum: Logical maximum value for this attribute. */ struct hid_sensor_hub_attribute_info { u32 usage_id; @@ -146,6 +148,7 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, /** * sensor_hub_input_attr_get_raw_value() - Synchronous read request +* @hsdev: Hub device instance. * @usage_id: Attribute usage id of parent physical device as per spec * @attr_usage_id: Attribute usage id as per spec * @report_id: Report id to look for @@ -160,6 +163,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, u32 attr_usage_id, u32 report_id); /** * sensor_hub_set_feature() - Feature set request +* @hsdev: Hub device instance. * @report_id: Report id to look for * @field_index: Field index inside a report * @value: Value to set @@ -172,6 +176,7 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, /** * sensor_hub_get_feature() - Feature get request +* @hsdev: Hub device instance. * @report_id: Report id to look for * @field_index: Field index inside a report * @value: Place holder for return value -- cgit v1.2.3 From 4b8164b91d9fdff4dbac0a742d076bdff7fda21b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 31 Jan 2015 20:08:47 -0500 Subject: new helper: dup_iter() Copy iter and kmemdup the underlying array for the copy. Returns a pointer to result of kmemdup() to be kfree()'d later. Signed-off-by: Al Viro --- include/linux/uio.h | 2 ++ mm/iov_iter.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'include') diff --git a/include/linux/uio.h b/include/linux/uio.h index 07a022641996..71880299ed48 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -98,6 +98,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, size_t maxsize, size_t *start); int iov_iter_npages(const struct iov_iter *i, int maxpages); +const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags); + static inline size_t iov_iter_count(struct iov_iter *i) { return i->count; diff --git a/mm/iov_iter.c b/mm/iov_iter.c index 827732047da1..9d96e283520c 100644 --- a/mm/iov_iter.c +++ b/mm/iov_iter.c @@ -751,3 +751,18 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages) return npages; } EXPORT_SYMBOL(iov_iter_npages); + +const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) +{ + *new = *old; + if (new->type & ITER_BVEC) + return new->bvec = kmemdup(new->bvec, + new->nr_segs * sizeof(struct bio_vec), + flags); + else + /* iovec and kvec have identical layout */ + return new->iov = kmemdup(new->iov, + new->nr_segs * sizeof(struct iovec), + flags); +} +EXPORT_SYMBOL(dup_iter); -- cgit v1.2.3 From 02cea3958664723a5d2236f0f0058de97c7e4693 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 5 Feb 2015 14:06:23 +0100 Subject: genirq: Provide disable_hardirq() For things like netpoll there is a need to disable an interrupt from atomic context. Currently netpoll uses disable_irq() which will sleep-wait on threaded handlers and thus forced_irqthreads breaks things. Provide disable_hardirq(), which uses synchronize_hardirq() to only wait for active hardirq handlers; also change synchronize_hardirq() to return the status of threaded handlers. This will allow one to try-disable an interrupt from atomic context, or in case of request_threaded_irq() to only wait for the hardirq part. Suggested-by: Sabrina Dubroca Signed-off-by: Peter Zijlstra (Intel) Cc: Arnd Bergmann Cc: David Miller Cc: Eyal Perry Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Quentin Lambert Cc: Randy Dunlap Cc: Russell King Link: http://lkml.kernel.org/r/20150205130623.GH5029@twins.programming.kicks-ass.net [ Fixed typos and such. ] Signed-off-by: Ingo Molnar --- include/linux/hardirq.h | 2 +- include/linux/interrupt.h | 1 + kernel/irq/manage.c | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index cba442ec3c66..f4af03404b97 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -9,7 +9,7 @@ extern void synchronize_irq(unsigned int irq); -extern void synchronize_hardirq(unsigned int irq); +extern bool synchronize_hardirq(unsigned int irq); #if defined(CONFIG_TINY_RCU) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index d9b05b5bf8c7..3bb01b9a379c 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -184,6 +184,7 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id); #endif extern void disable_irq_nosync(unsigned int irq); +extern bool disable_hardirq(unsigned int irq); extern void disable_irq(unsigned int irq); extern void disable_percpu_irq(unsigned int irq); extern void enable_irq(unsigned int irq); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 196a06fbc122..03329c2287eb 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -68,14 +68,20 @@ static void __synchronize_hardirq(struct irq_desc *desc) * Do not use this for shutdown scenarios where you must be sure * that all parts (hardirq and threaded handler) have completed. * + * Returns: false if a threaded handler is active. + * * This function may be called - with care - from IRQ context. */ -void synchronize_hardirq(unsigned int irq) +bool synchronize_hardirq(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); - if (desc) + if (desc) { __synchronize_hardirq(desc); + return !atomic_read(&desc->threads_active); + } + + return true; } EXPORT_SYMBOL(synchronize_hardirq); @@ -440,6 +446,32 @@ void disable_irq(unsigned int irq) } EXPORT_SYMBOL(disable_irq); +/** + * disable_hardirq - disables an irq and waits for hardirq completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending hard IRQ handlers for this + * interrupt to complete before returning. If you use this function while + * holding a resource the hard IRQ handler may need you will deadlock. + * + * When used to optimistically disable an interrupt from atomic context + * the return value must be checked. + * + * Returns: false if a threaded handler is active. + * + * This function may be called - with care - from IRQ context. + */ +bool disable_hardirq(unsigned int irq) +{ + if (!__disable_irq_nosync(irq)) + return synchronize_hardirq(irq); + + return false; +} +EXPORT_SYMBOL_GPL(disable_hardirq); + void __enable_irq(struct irq_desc *desc, unsigned int irq) { switch (desc->depth) { -- cgit v1.2.3 From bd624d75db21ea5402f9ecf4450b311794d80352 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 13 Feb 2015 08:54:56 +0800 Subject: clockevents: Introduce mode specific callbacks It is not possible for the clockevents core to know which modes (other than those with a corresponding feature flag) are supported by a particular implementation. And drivers are expected to handle transition to all modes elegantly, as ->set_mode() would be issued for them unconditionally. Now, adding support for a new mode complicates things a bit if we want to use the legacy ->set_mode() callback. We need to closely review all clockevents drivers to see if they would break on addition of a new mode. And after such reviews, it is found that we have to do non-trivial changes to most of the drivers [1]. Introduce mode-specific set_mode_*() callbacks, some of which the drivers may or may not implement. A missing callback would clearly convey the message that the corresponding mode isn't supported. A driver may still choose to keep supporting the legacy ->set_mode() callback, but ->set_mode() wouldn't be supporting any new modes beyond RESUME. If a driver wants to benefit from using a new mode, it would be required to migrate to the mode specific callbacks. The legacy ->set_mode() callback and the newly introduced mode-specific callbacks are mutually exclusive. Only one of them should be supported by the driver. Sanity check is done at the time of registration to distinguish between optional and required callbacks and to make error recovery and handling simpler. If the legacy ->set_mode() callback is provided, all mode specific ones would be ignored by the core but a warning is thrown if they are present. Call sites calling ->set_mode() directly are also updated to use __clockevents_set_mode() instead, as ->set_mode() may not be available anymore for few drivers. [1] https://lkml.org/lkml/2014/12/9/605 [2] https://lkml.org/lkml/2015/1/23/255 Suggested-by: Thomas Gleixner [2] Signed-off-by: Viresh Kumar Signed-off-by: Peter Zijlstra (Intel) Cc: Daniel Lezcano Cc: Frederic Weisbecker Cc: John Stultz Cc: Kevin Hilman Cc: Linus Torvalds Cc: Preeti U Murthy Cc: linaro-kernel@lists.linaro.org Cc: linaro-networking@linaro.org Link: http://lkml.kernel.org/r/792d59a40423f0acffc9bb0bec9de1341a06fa02.1423788565.git.viresh.kumar@linaro.org Signed-off-by: Ingo Molnar --- include/linux/clockchips.h | 21 +++++++++-- kernel/time/clockevents.c | 88 ++++++++++++++++++++++++++++++++++++++++++++-- kernel/time/timer_list.c | 32 +++++++++++++++-- 3 files changed, 134 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 2e4cb67f6e56..59af26b54d15 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -39,6 +39,8 @@ enum clock_event_mode { CLOCK_EVT_MODE_PERIODIC, CLOCK_EVT_MODE_ONESHOT, CLOCK_EVT_MODE_RESUME, + + /* Legacy ->set_mode() callback doesn't support below modes */ }; /* @@ -81,7 +83,11 @@ enum clock_event_mode { * @mode: operating mode assigned by the management code * @features: features * @retries: number of forced programming retries - * @set_mode: set mode function + * @set_mode: legacy set mode function, only for modes <= CLOCK_EVT_MODE_RESUME. + * @set_mode_periodic: switch mode to periodic, if !set_mode + * @set_mode_oneshot: switch mode to oneshot, if !set_mode + * @set_mode_shutdown: switch mode to shutdown, if !set_mode + * @set_mode_resume: resume clkevt device, if !set_mode * @broadcast: function to broadcast events * @min_delta_ticks: minimum delta value in ticks stored for reconfiguration * @max_delta_ticks: maximum delta value in ticks stored for reconfiguration @@ -108,9 +114,20 @@ struct clock_event_device { unsigned int features; unsigned long retries; - void (*broadcast)(const struct cpumask *mask); + /* + * Mode transition callback(s): Only one of the two groups should be + * defined: + * - set_mode(), only for modes <= CLOCK_EVT_MODE_RESUME. + * - set_mode_{shutdown|periodic|oneshot|resume}(). + */ void (*set_mode)(enum clock_event_mode mode, struct clock_event_device *); + int (*set_mode_periodic)(struct clock_event_device *); + int (*set_mode_oneshot)(struct clock_event_device *); + int (*set_mode_shutdown)(struct clock_event_device *); + int (*set_mode_resume)(struct clock_event_device *); + + void (*broadcast)(const struct cpumask *mask); void (*suspend)(struct clock_event_device *); void (*resume)(struct clock_event_device *); unsigned long min_delta_ticks; diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 55449909f114..489642b08d64 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -94,6 +94,57 @@ u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt) } EXPORT_SYMBOL_GPL(clockevent_delta2ns); +static int __clockevents_set_mode(struct clock_event_device *dev, + enum clock_event_mode mode) +{ + /* Transition with legacy set_mode() callback */ + if (dev->set_mode) { + /* Legacy callback doesn't support new modes */ + if (mode > CLOCK_EVT_MODE_RESUME) + return -ENOSYS; + dev->set_mode(mode, dev); + return 0; + } + + if (dev->features & CLOCK_EVT_FEAT_DUMMY) + return 0; + + /* Transition with new mode-specific callbacks */ + switch (mode) { + case CLOCK_EVT_MODE_UNUSED: + /* + * This is an internal state, which is guaranteed to go from + * SHUTDOWN to UNUSED. No driver interaction required. + */ + return 0; + + case CLOCK_EVT_MODE_SHUTDOWN: + return dev->set_mode_shutdown(dev); + + case CLOCK_EVT_MODE_PERIODIC: + /* Core internal bug */ + if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC)) + return -ENOSYS; + return dev->set_mode_periodic(dev); + + case CLOCK_EVT_MODE_ONESHOT: + /* Core internal bug */ + if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) + return -ENOSYS; + return dev->set_mode_oneshot(dev); + + case CLOCK_EVT_MODE_RESUME: + /* Optional callback */ + if (dev->set_mode_resume) + return dev->set_mode_resume(dev); + else + return 0; + + default: + return -ENOSYS; + } +} + /** * clockevents_set_mode - set the operating mode of a clock event device * @dev: device to modify @@ -105,7 +156,9 @@ void clockevents_set_mode(struct clock_event_device *dev, enum clock_event_mode mode) { if (dev->mode != mode) { - dev->set_mode(mode, dev); + if (__clockevents_set_mode(dev, mode)) + return; + dev->mode = mode; /* @@ -373,6 +426,35 @@ int clockevents_unbind_device(struct clock_event_device *ced, int cpu) } EXPORT_SYMBOL_GPL(clockevents_unbind); +/* Sanity check of mode transition callbacks */ +static int clockevents_sanity_check(struct clock_event_device *dev) +{ + /* Legacy set_mode() callback */ + if (dev->set_mode) { + /* We shouldn't be supporting new modes now */ + WARN_ON(dev->set_mode_periodic || dev->set_mode_oneshot || + dev->set_mode_shutdown || dev->set_mode_resume); + return 0; + } + + if (dev->features & CLOCK_EVT_FEAT_DUMMY) + return 0; + + /* New mode-specific callbacks */ + if (!dev->set_mode_shutdown) + return -EINVAL; + + if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) && + !dev->set_mode_periodic) + return -EINVAL; + + if ((dev->features & CLOCK_EVT_FEAT_ONESHOT) && + !dev->set_mode_oneshot) + return -EINVAL; + + return 0; +} + /** * clockevents_register_device - register a clock event device * @dev: device to register @@ -382,6 +464,8 @@ void clockevents_register_device(struct clock_event_device *dev) unsigned long flags; BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED); + BUG_ON(clockevents_sanity_check(dev)); + if (!dev->cpumask) { WARN_ON(num_possible_cpus() > 1); dev->cpumask = cpumask_of(smp_processor_id()); @@ -449,7 +533,7 @@ int __clockevents_update_freq(struct clock_event_device *dev, u32 freq) return clockevents_program_event(dev, dev->next_event, false); if (dev->mode == CLOCK_EVT_MODE_PERIODIC) - dev->set_mode(CLOCK_EVT_MODE_PERIODIC, dev); + return __clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC); return 0; } diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index 61ed862cdd37..2cfd19485824 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -228,9 +228,35 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu) print_name_offset(m, dev->set_next_event); SEQ_printf(m, "\n"); - SEQ_printf(m, " set_mode: "); - print_name_offset(m, dev->set_mode); - SEQ_printf(m, "\n"); + if (dev->set_mode) { + SEQ_printf(m, " set_mode: "); + print_name_offset(m, dev->set_mode); + SEQ_printf(m, "\n"); + } else { + if (dev->set_mode_shutdown) { + SEQ_printf(m, " shutdown: "); + print_name_offset(m, dev->set_mode_shutdown); + SEQ_printf(m, "\n"); + } + + if (dev->set_mode_periodic) { + SEQ_printf(m, " periodic: "); + print_name_offset(m, dev->set_mode_periodic); + SEQ_printf(m, "\n"); + } + + if (dev->set_mode_oneshot) { + SEQ_printf(m, " oneshot: "); + print_name_offset(m, dev->set_mode_oneshot); + SEQ_printf(m, "\n"); + } + + if (dev->set_mode_resume) { + SEQ_printf(m, " resume: "); + print_name_offset(m, dev->set_mode_resume); + SEQ_printf(m, "\n"); + } + } SEQ_printf(m, " event_handler: "); print_name_offset(m, dev->event_handler); -- cgit v1.2.3 From 27ac905b8f88d28779b0661809286b5ba2817d37 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 4 Nov 2014 21:55:57 -0500 Subject: perf/x86/intel: Reduce lbr_sel_map[] size The index of lbr_sel_map is bit value of perf branch_sample_type. PERF_SAMPLE_BRANCH_MAX is 1024 at present, so each lbr_sel_map uses 4096 bytes. By using bit shift as index, we can reduce lbr_sel_map size to 40 bytes. This patch defines 'bit shift' for branch types, and use 'bit shift' to define lbr_sel_maps. Signed-off-by: Yan, Zheng Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Stephane Eranian Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Paul Mackerras Cc: Vince Weaver Cc: jolsa@redhat.com Cc: linux-api@vger.kernel.org Link: http://lkml.kernel.org/r/1415156173-10035-2-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.h | 4 +++ arch/x86/kernel/cpu/perf_event_intel_lbr.c | 54 ++++++++++++++---------------- include/uapi/linux/perf_event.h | 49 +++++++++++++++++++-------- 3 files changed, 64 insertions(+), 43 deletions(-) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index df525d2be1e8..0c45b22495dc 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -515,6 +515,10 @@ struct x86_pmu { struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr); }; +enum { + PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE = PERF_SAMPLE_BRANCH_MAX_SHIFT, +}; + #define x86_add_quirk(func_) \ do { \ static struct x86_pmu_quirk __quirk __initdata = { \ diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index 58f1a94beaf0..8bc078f43a82 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -69,10 +69,6 @@ static enum { #define LBR_FROM_FLAG_IN_TX (1ULL << 62) #define LBR_FROM_FLAG_ABORT (1ULL << 61) -#define for_each_branch_sample_type(x) \ - for ((x) = PERF_SAMPLE_BRANCH_USER; \ - (x) < PERF_SAMPLE_BRANCH_MAX; (x) <<= 1) - /* * x86control flow change classification * x86control flow changes include branches, interrupts, traps, faults @@ -403,14 +399,14 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event) { struct hw_perf_event_extra *reg; u64 br_type = event->attr.branch_sample_type; - u64 mask = 0, m; - u64 v; + u64 mask = 0, v; + int i; - for_each_branch_sample_type(m) { - if (!(br_type & m)) + for (i = 0; i < PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE; i++) { + if (!(br_type & (1ULL << i))) continue; - v = x86_pmu.lbr_sel_map[m]; + v = x86_pmu.lbr_sel_map[i]; if (v == LBR_NOT_SUPP) return -EOPNOTSUPP; @@ -678,35 +674,35 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) /* * Map interface branch filters onto LBR filters */ -static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = { - [PERF_SAMPLE_BRANCH_ANY] = LBR_ANY, - [PERF_SAMPLE_BRANCH_USER] = LBR_USER, - [PERF_SAMPLE_BRANCH_KERNEL] = LBR_KERNEL, - [PERF_SAMPLE_BRANCH_HV] = LBR_IGN, - [PERF_SAMPLE_BRANCH_ANY_RETURN] = LBR_RETURN | LBR_REL_JMP - | LBR_IND_JMP | LBR_FAR, +static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE] = { + [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, + [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, + [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, + [PERF_SAMPLE_BRANCH_HV_SHIFT] = LBR_IGN, + [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT] = LBR_RETURN | LBR_REL_JMP + | LBR_IND_JMP | LBR_FAR, /* * NHM/WSM erratum: must include REL_JMP+IND_JMP to get CALL branches */ - [PERF_SAMPLE_BRANCH_ANY_CALL] = + [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] = LBR_REL_CALL | LBR_IND_CALL | LBR_REL_JMP | LBR_IND_JMP | LBR_FAR, /* * NHM/WSM erratum: must include IND_JMP to capture IND_CALL */ - [PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL | LBR_IND_JMP, - [PERF_SAMPLE_BRANCH_COND] = LBR_JCC, + [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL | LBR_IND_JMP, + [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, }; -static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = { - [PERF_SAMPLE_BRANCH_ANY] = LBR_ANY, - [PERF_SAMPLE_BRANCH_USER] = LBR_USER, - [PERF_SAMPLE_BRANCH_KERNEL] = LBR_KERNEL, - [PERF_SAMPLE_BRANCH_HV] = LBR_IGN, - [PERF_SAMPLE_BRANCH_ANY_RETURN] = LBR_RETURN | LBR_FAR, - [PERF_SAMPLE_BRANCH_ANY_CALL] = LBR_REL_CALL | LBR_IND_CALL - | LBR_FAR, - [PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL, - [PERF_SAMPLE_BRANCH_COND] = LBR_JCC, +static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE] = { + [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, + [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, + [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, + [PERF_SAMPLE_BRANCH_HV_SHIFT] = LBR_IGN, + [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT] = LBR_RETURN | LBR_FAR, + [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] = LBR_REL_CALL | LBR_IND_CALL + | LBR_FAR, + [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL, + [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, }; /* core */ diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 9b79abbd1ab8..e46b93279e3d 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -152,21 +152,42 @@ enum perf_event_sample_format { * The branch types can be combined, however BRANCH_ANY covers all types * of branches and therefore it supersedes all the other types. */ +enum perf_branch_sample_type_shift { + PERF_SAMPLE_BRANCH_USER_SHIFT = 0, /* user branches */ + PERF_SAMPLE_BRANCH_KERNEL_SHIFT = 1, /* kernel branches */ + PERF_SAMPLE_BRANCH_HV_SHIFT = 2, /* hypervisor branches */ + + PERF_SAMPLE_BRANCH_ANY_SHIFT = 3, /* any branch types */ + PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT = 4, /* any call branch */ + PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT = 5, /* any return branch */ + PERF_SAMPLE_BRANCH_IND_CALL_SHIFT = 6, /* indirect calls */ + PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT = 7, /* transaction aborts */ + PERF_SAMPLE_BRANCH_IN_TX_SHIFT = 8, /* in transaction */ + PERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9, /* not in transaction */ + PERF_SAMPLE_BRANCH_COND_SHIFT = 10, /* conditional branches */ + + PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ +}; + enum perf_branch_sample_type { - PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */ - PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */ - PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */ - - PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */ - PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */ - PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */ - PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */ - PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */ - PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */ - PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */ - PERF_SAMPLE_BRANCH_COND = 1U << 10, /* conditional branches */ - - PERF_SAMPLE_BRANCH_MAX = 1U << 11, /* non-ABI */ + PERF_SAMPLE_BRANCH_USER = 1U << PERF_SAMPLE_BRANCH_USER_SHIFT, + PERF_SAMPLE_BRANCH_KERNEL = 1U << PERF_SAMPLE_BRANCH_KERNEL_SHIFT, + PERF_SAMPLE_BRANCH_HV = 1U << PERF_SAMPLE_BRANCH_HV_SHIFT, + + PERF_SAMPLE_BRANCH_ANY = 1U << PERF_SAMPLE_BRANCH_ANY_SHIFT, + PERF_SAMPLE_BRANCH_ANY_CALL = + 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT, + PERF_SAMPLE_BRANCH_ANY_RETURN = + 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT, + PERF_SAMPLE_BRANCH_IND_CALL = + 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT, + PERF_SAMPLE_BRANCH_ABORT_TX = + 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT, + PERF_SAMPLE_BRANCH_IN_TX = 1U << PERF_SAMPLE_BRANCH_IN_TX_SHIFT, + PERF_SAMPLE_BRANCH_NO_TX = 1U << PERF_SAMPLE_BRANCH_NO_TX_SHIFT, + PERF_SAMPLE_BRANCH_COND = 1U << PERF_SAMPLE_BRANCH_COND_SHIFT, + + PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, }; #define PERF_SAMPLE_BRANCH_PLM_ALL \ -- cgit v1.2.3 From ba532500c5651a4be4108acc64ed99a95cb005b3 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 4 Nov 2014 21:55:58 -0500 Subject: perf: Introduce pmu context switch callback The callback is invoked when process is scheduled in or out. It provides mechanism for later patches to save/store the LBR stack. For the schedule in case, the callback is invoked at the same place that flush branch stack callback is invoked. So it also can replace the flush branch stack callback. To avoid unnecessary overhead, the callback is enabled only when there are events use the LBR stack. Signed-off-by: Yan, Zheng Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Paul Mackerras Cc: Vince Weaver Cc: eranian@google.com Cc: jolsa@redhat.com Link: http://lkml.kernel.org/r/1415156173-10035-3-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 7 +++++ arch/x86/kernel/cpu/perf_event.h | 2 ++ include/linux/perf_event.h | 9 +++++++ kernel/events/core.c | 57 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index b71a7f86d68a..0efbd6cc2966 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1914,6 +1914,12 @@ static const struct attribute_group *x86_pmu_attr_groups[] = { NULL, }; +static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) +{ + if (x86_pmu.sched_task) + x86_pmu.sched_task(ctx, sched_in); +} + static void x86_pmu_flush_branch_stack(void) { if (x86_pmu.flush_branch_stack) @@ -1950,6 +1956,7 @@ static struct pmu pmu = { .event_idx = x86_pmu_event_idx, .flush_branch_stack = x86_pmu_flush_branch_stack, + .sched_task = x86_pmu_sched_task, }; void arch_perf_update_userpage(struct perf_event *event, diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 0c45b22495dc..211b54c0c00c 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -473,6 +473,8 @@ struct x86_pmu { void (*check_microcode)(void); void (*flush_branch_stack)(void); + void (*sched_task)(struct perf_event_context *ctx, + bool sched_in); /* * Intel Arch Perfmon v2+ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 33262004c310..fbab6235d053 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -265,6 +265,13 @@ struct pmu { * flush branch stack on context-switches (needed in cpu-wide mode) */ void (*flush_branch_stack) (void); + + /* + * context-switches callback + */ + void (*sched_task) (struct perf_event_context *ctx, + bool sched_in); + }; /** @@ -558,6 +565,8 @@ extern void perf_event_delayed_put(struct task_struct *task); extern void perf_event_print_debug(void); extern void perf_pmu_disable(struct pmu *pmu); extern void perf_pmu_enable(struct pmu *pmu); +extern void perf_sched_cb_dec(struct pmu *pmu); +extern void perf_sched_cb_inc(struct pmu *pmu); extern int perf_event_task_disable(void); extern int perf_event_task_enable(void); extern int perf_event_refresh(struct perf_event *event, int refresh); diff --git a/kernel/events/core.c b/kernel/events/core.c index fef45b4bb5f8..6c8b31b7efb6 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -154,6 +154,7 @@ enum event_type_t { struct static_key_deferred perf_sched_events __read_mostly; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events); +static DEFINE_PER_CPU(int, perf_sched_cb_usages); static atomic_t nr_mmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; @@ -2577,6 +2578,56 @@ unlock: } } +void perf_sched_cb_dec(struct pmu *pmu) +{ + this_cpu_dec(perf_sched_cb_usages); +} + +void perf_sched_cb_inc(struct pmu *pmu) +{ + this_cpu_inc(perf_sched_cb_usages); +} + +/* + * This function provides the context switch callback to the lower code + * layer. It is invoked ONLY when the context switch callback is enabled. + */ +static void perf_pmu_sched_task(struct task_struct *prev, + struct task_struct *next, + bool sched_in) +{ + struct perf_cpu_context *cpuctx; + struct pmu *pmu; + unsigned long flags; + + if (prev == next) + return; + + local_irq_save(flags); + + rcu_read_lock(); + + list_for_each_entry_rcu(pmu, &pmus, entry) { + if (pmu->sched_task) { + cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); + + perf_ctx_lock(cpuctx, cpuctx->task_ctx); + + perf_pmu_disable(pmu); + + pmu->sched_task(cpuctx->task_ctx, sched_in); + + perf_pmu_enable(pmu); + + perf_ctx_unlock(cpuctx, cpuctx->task_ctx); + } + } + + rcu_read_unlock(); + + local_irq_restore(flags); +} + #define for_each_task_context_nr(ctxn) \ for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++) @@ -2596,6 +2647,9 @@ void __perf_event_task_sched_out(struct task_struct *task, { int ctxn; + if (__this_cpu_read(perf_sched_cb_usages)) + perf_pmu_sched_task(task, next, false); + for_each_task_context_nr(ctxn) perf_event_context_sched_out(task, ctxn, next); @@ -2847,6 +2901,9 @@ void __perf_event_task_sched_in(struct task_struct *prev, /* check for system-wide branch_stack events */ if (atomic_read(this_cpu_ptr(&perf_branch_stack_events))) perf_branch_stack_sched_in(prev, task); + + if (__this_cpu_read(perf_sched_cb_usages)) + perf_pmu_sched_task(prev, task, true); } static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) -- cgit v1.2.3 From 2a0ad3b326a9024ba86dca4028499d31fa0c6c4d Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 4 Nov 2014 21:55:59 -0500 Subject: perf/x86/intel: Use context switch callback to flush LBR stack Previous commit introduces context switch callback, its function overlaps with the flush branch stack callback. So we can use the context switch callback to flush LBR stack. This patch adds code that uses the flush branch callback to flush the LBR stack when task is being scheduled in. The callback is enabled only when there are events use the LBR hardware. This patch also removes all old flush branch stack code. Signed-off-by: Yan, Zheng Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Paul Mackerras Cc: Vince Weaver Cc: eranian@google.com Cc: jolsa@redhat.com Link: http://lkml.kernel.org/r/1415156173-10035-4-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 7 --- arch/x86/kernel/cpu/perf_event.h | 3 +- arch/x86/kernel/cpu/perf_event_intel.c | 14 +----- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 27 +++++++++++ include/linux/perf_event.h | 1 - kernel/events/core.c | 77 ------------------------------ 6 files changed, 30 insertions(+), 99 deletions(-) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 0efbd6cc2966..6b1fd26a37cf 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1920,12 +1920,6 @@ static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) x86_pmu.sched_task(ctx, sched_in); } -static void x86_pmu_flush_branch_stack(void) -{ - if (x86_pmu.flush_branch_stack) - x86_pmu.flush_branch_stack(); -} - void perf_check_microcode(void) { if (x86_pmu.check_microcode) @@ -1955,7 +1949,6 @@ static struct pmu pmu = { .commit_txn = x86_pmu_commit_txn, .event_idx = x86_pmu_event_idx, - .flush_branch_stack = x86_pmu_flush_branch_stack, .sched_task = x86_pmu_sched_task, }; diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 211b54c0c00c..949d0083a29e 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -472,7 +472,6 @@ struct x86_pmu { void (*cpu_dead)(int cpu); void (*check_microcode)(void); - void (*flush_branch_stack)(void); void (*sched_task)(struct perf_event_context *ctx, bool sched_in); @@ -733,6 +732,8 @@ void intel_pmu_pebs_disable_all(void); void intel_ds_init(void); +void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in); + void intel_pmu_lbr_reset(void); void intel_pmu_lbr_enable(struct perf_event *event); diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 498b6d967138..424fbf74dee7 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2044,18 +2044,6 @@ static void intel_pmu_cpu_dying(int cpu) fini_debug_store_on_cpu(cpu); } -static void intel_pmu_flush_branch_stack(void) -{ - /* - * Intel LBR does not tag entries with the - * PID of the current task, then we need to - * flush it on ctxsw - * For now, we simply reset it - */ - if (x86_pmu.lbr_nr) - intel_pmu_lbr_reset(); -} - PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); PMU_FORMAT_ATTR(ldlat, "config1:0-15"); @@ -2107,7 +2095,7 @@ static __initconst const struct x86_pmu intel_pmu = { .cpu_starting = intel_pmu_cpu_starting, .cpu_dying = intel_pmu_cpu_dying, .guest_get_msrs = intel_guest_get_msrs, - .flush_branch_stack = intel_pmu_flush_branch_stack, + .sched_task = intel_pmu_lbr_sched_task, }; static __init void intel_clovertown_quirk(void) diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index 8bc078f43a82..c0e23c5f85bb 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -177,6 +177,31 @@ void intel_pmu_lbr_reset(void) intel_pmu_lbr_reset_64(); } +void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + + if (!x86_pmu.lbr_nr) + return; + + /* + * When sampling the branck stack in system-wide, it may be + * necessary to flush the stack on context switch. This happens + * when the branch stack does not tag its entries with the pid + * of the current task. Otherwise it becomes impossible to + * associate a branch entry with a task. This ambiguity is more + * likely to appear when the branch stack supports priv level + * filtering and the user sets it to monitor only at the user + * level (which could be a useful measurement in system-wide + * mode). In that case, the risk is high of having a branch + * stack with branch from multiple tasks. + */ + if (sched_in) { + intel_pmu_lbr_reset(); + cpuc->lbr_context = ctx; + } +} + void intel_pmu_lbr_enable(struct perf_event *event) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); @@ -195,6 +220,7 @@ void intel_pmu_lbr_enable(struct perf_event *event) cpuc->br_sel = event->hw.branch_reg.reg; cpuc->lbr_users++; + perf_sched_cb_inc(event->ctx->pmu); } void intel_pmu_lbr_disable(struct perf_event *event) @@ -206,6 +232,7 @@ void intel_pmu_lbr_disable(struct perf_event *event) cpuc->lbr_users--; WARN_ON_ONCE(cpuc->lbr_users < 0); + perf_sched_cb_dec(event->ctx->pmu); if (cpuc->enabled && !cpuc->lbr_users) { __intel_pmu_lbr_disable(); diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index fbab6235d053..c7007a564440 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -511,7 +511,6 @@ struct perf_event_context { u64 generation; int pin_count; int nr_cgroups; /* cgroup evts */ - int nr_branch_stack; /* branch_stack evt */ struct rcu_head rcu_head; struct delayed_work orphans_remove; diff --git a/kernel/events/core.c b/kernel/events/core.c index 6c8b31b7efb6..f563ce767f93 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -153,7 +153,6 @@ enum event_type_t { */ struct static_key_deferred perf_sched_events __read_mostly; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); -static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events); static DEFINE_PER_CPU(int, perf_sched_cb_usages); static atomic_t nr_mmap_events __read_mostly; @@ -1240,9 +1239,6 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) if (is_cgroup_event(event)) ctx->nr_cgroups++; - if (has_branch_stack(event)) - ctx->nr_branch_stack++; - list_add_rcu(&event->event_entry, &ctx->event_list); ctx->nr_events++; if (event->attr.inherit_stat) @@ -1409,9 +1405,6 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) cpuctx->cgrp = NULL; } - if (has_branch_stack(event)) - ctx->nr_branch_stack--; - ctx->nr_events--; if (event->attr.inherit_stat) ctx->nr_stat--; @@ -2808,64 +2801,6 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx, perf_ctx_unlock(cpuctx, ctx); } -/* - * When sampling the branck stack in system-wide, it may be necessary - * to flush the stack on context switch. This happens when the branch - * stack does not tag its entries with the pid of the current task. - * Otherwise it becomes impossible to associate a branch entry with a - * task. This ambiguity is more likely to appear when the branch stack - * supports priv level filtering and the user sets it to monitor only - * at the user level (which could be a useful measurement in system-wide - * mode). In that case, the risk is high of having a branch stack with - * branch from multiple tasks. Flushing may mean dropping the existing - * entries or stashing them somewhere in the PMU specific code layer. - * - * This function provides the context switch callback to the lower code - * layer. It is invoked ONLY when there is at least one system-wide context - * with at least one active event using taken branch sampling. - */ -static void perf_branch_stack_sched_in(struct task_struct *prev, - struct task_struct *task) -{ - struct perf_cpu_context *cpuctx; - struct pmu *pmu; - unsigned long flags; - - /* no need to flush branch stack if not changing task */ - if (prev == task) - return; - - local_irq_save(flags); - - rcu_read_lock(); - - list_for_each_entry_rcu(pmu, &pmus, entry) { - cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); - - /* - * check if the context has at least one - * event using PERF_SAMPLE_BRANCH_STACK - */ - if (cpuctx->ctx.nr_branch_stack > 0 - && pmu->flush_branch_stack) { - - perf_ctx_lock(cpuctx, cpuctx->task_ctx); - - perf_pmu_disable(pmu); - - pmu->flush_branch_stack(); - - perf_pmu_enable(pmu); - - perf_ctx_unlock(cpuctx, cpuctx->task_ctx); - } - } - - rcu_read_unlock(); - - local_irq_restore(flags); -} - /* * Called from scheduler to add the events of the current task * with interrupts disabled. @@ -2898,10 +2833,6 @@ void __perf_event_task_sched_in(struct task_struct *prev, if (atomic_read(this_cpu_ptr(&perf_cgroup_events))) perf_cgroup_sched_in(prev, task); - /* check for system-wide branch_stack events */ - if (atomic_read(this_cpu_ptr(&perf_branch_stack_events))) - perf_branch_stack_sched_in(prev, task); - if (__this_cpu_read(perf_sched_cb_usages)) perf_pmu_sched_task(prev, task, true); } @@ -3480,10 +3411,6 @@ static void unaccount_event_cpu(struct perf_event *event, int cpu) if (event->parent) return; - if (has_branch_stack(event)) { - if (!(event->attach_state & PERF_ATTACH_TASK)) - atomic_dec(&per_cpu(perf_branch_stack_events, cpu)); - } if (is_cgroup_event(event)) atomic_dec(&per_cpu(perf_cgroup_events, cpu)); } @@ -7139,10 +7066,6 @@ static void account_event_cpu(struct perf_event *event, int cpu) if (event->parent) return; - if (has_branch_stack(event)) { - if (!(event->attach_state & PERF_ATTACH_TASK)) - atomic_inc(&per_cpu(perf_branch_stack_events, cpu)); - } if (is_cgroup_event(event)) atomic_inc(&per_cpu(perf_cgroup_events, cpu)); } -- cgit v1.2.3 From 4af57ef28c2c1047fda9e1a5be02aa7a6a69cf9e Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 4 Nov 2014 21:56:01 -0500 Subject: perf: Add pmu specific data for perf task context Introduce a new flag PERF_ATTACH_TASK_DATA for perf event's attach stata. The flag is set by PMU's event_init() callback, it indicates that perf event needs PMU specific data. The PMU specific data are initialized to zeros. Later patches will use PMU specific data to save LBR stack. Signed-off-by: Yan, Zheng Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Paul Mackerras Cc: eranian@google.com Cc: jolsa@redhat.com Link: http://lkml.kernel.org/r/1415156173-10035-6-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 6 ++++++ kernel/events/core.c | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index c7007a564440..270cd0173e61 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -271,6 +271,10 @@ struct pmu { */ void (*sched_task) (struct perf_event_context *ctx, bool sched_in); + /* + * PMU specific data size + */ + size_t task_ctx_size; }; @@ -307,6 +311,7 @@ struct swevent_hlist { #define PERF_ATTACH_CONTEXT 0x01 #define PERF_ATTACH_GROUP 0x02 #define PERF_ATTACH_TASK 0x04 +#define PERF_ATTACH_TASK_DATA 0x08 struct perf_cgroup; struct ring_buffer; @@ -511,6 +516,7 @@ struct perf_event_context { u64 generation; int pin_count; int nr_cgroups; /* cgroup evts */ + void *task_ctx_data; /* pmu specific data */ struct rcu_head rcu_head; struct delayed_work orphans_remove; diff --git a/kernel/events/core.c b/kernel/events/core.c index f563ce767f93..688086bb7144 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -905,6 +905,15 @@ static void get_ctx(struct perf_event_context *ctx) WARN_ON(!atomic_inc_not_zero(&ctx->refcount)); } +static void free_ctx(struct rcu_head *head) +{ + struct perf_event_context *ctx; + + ctx = container_of(head, struct perf_event_context, rcu_head); + kfree(ctx->task_ctx_data); + kfree(ctx); +} + static void put_ctx(struct perf_event_context *ctx) { if (atomic_dec_and_test(&ctx->refcount)) { @@ -912,7 +921,7 @@ static void put_ctx(struct perf_event_context *ctx) put_ctx(ctx->parent_ctx); if (ctx->task) put_task_struct(ctx->task); - kfree_rcu(ctx, rcu_head); + call_rcu(&ctx->rcu_head, free_ctx); } } @@ -3309,12 +3318,15 @@ errout: * Returns a matching context with refcount and pincount. */ static struct perf_event_context * -find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) +find_get_context(struct pmu *pmu, struct task_struct *task, + struct perf_event *event) { struct perf_event_context *ctx, *clone_ctx = NULL; struct perf_cpu_context *cpuctx; + void *task_ctx_data = NULL; unsigned long flags; int ctxn, err; + int cpu = event->cpu; if (!task) { /* Must be root to operate on a CPU event: */ @@ -3342,11 +3354,24 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) if (ctxn < 0) goto errout; + if (event->attach_state & PERF_ATTACH_TASK_DATA) { + task_ctx_data = kzalloc(pmu->task_ctx_size, GFP_KERNEL); + if (!task_ctx_data) { + err = -ENOMEM; + goto errout; + } + } + retry: ctx = perf_lock_task_context(task, ctxn, &flags); if (ctx) { clone_ctx = unclone_ctx(ctx); ++ctx->pin_count; + + if (task_ctx_data && !ctx->task_ctx_data) { + ctx->task_ctx_data = task_ctx_data; + task_ctx_data = NULL; + } raw_spin_unlock_irqrestore(&ctx->lock, flags); if (clone_ctx) @@ -3357,6 +3382,11 @@ retry: if (!ctx) goto errout; + if (task_ctx_data) { + ctx->task_ctx_data = task_ctx_data; + task_ctx_data = NULL; + } + err = 0; mutex_lock(&task->perf_event_mutex); /* @@ -3383,9 +3413,11 @@ retry: } } + kfree(task_ctx_data); return ctx; errout: + kfree(task_ctx_data); return ERR_PTR(err); } @@ -7559,7 +7591,7 @@ SYSCALL_DEFINE5(perf_event_open, /* * Get the target context (task or percpu): */ - ctx = find_get_context(pmu, task, event->cpu); + ctx = find_get_context(pmu, task, event); if (IS_ERR(ctx)) { err = PTR_ERR(ctx); goto err_alloc; @@ -7765,7 +7797,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, account_event(event); - ctx = find_get_context(event->pmu, task, cpu); + ctx = find_get_context(event->pmu, task, event); if (IS_ERR(ctx)) { err = PTR_ERR(ctx); goto err_free; -- cgit v1.2.3 From a46a23000198d929391aa9dac8de68734efa2703 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 4 Nov 2014 21:56:06 -0500 Subject: perf: Simplify the branch stack check Use event->attr.branch_sample_type to replace intel_pmu_needs_lbr_smpl() for avoiding duplicated code that implicitly enables the LBR. Currently, branch stack can be enabled by user explicitly requesting branch sampling or implicit branch sampling to correct PEBS skid. For user explicitly requested branch sampling, the branch_sample_type is explicitly set by user. For PEBS case, the branch_sample_type is also implicitly set to PERF_SAMPLE_BRANCH_ANY in x86_pmu_hw_config. Signed-off-by: Yan, Zheng Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Paul Mackerras Cc: eranian@google.com Cc: jolsa@redhat.com Link: http://lkml.kernel.org/r/1415156173-10035-11-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 20 +++----------------- include/linux/perf_event.h | 5 +++++ kernel/events/core.c | 3 +++ 3 files changed, 11 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index a485ba124476..9f1dd18fa395 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1029,20 +1029,6 @@ static __initconst const u64 slm_hw_cache_event_ids }, }; -static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event) -{ - /* user explicitly requested branch sampling */ - if (has_branch_stack(event)) - return true; - - /* implicit branch sampling to correct PEBS skid */ - if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1 && - x86_pmu.intel_cap.pebs_format < 2) - return true; - - return false; -} - static void intel_pmu_disable_all(void) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); @@ -1207,7 +1193,7 @@ static void intel_pmu_disable_event(struct perf_event *event) * must disable before any actual event * because any event may be combined with LBR */ - if (intel_pmu_needs_lbr_smpl(event)) + if (needs_branch_stack(event)) intel_pmu_lbr_disable(event); if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) { @@ -1268,7 +1254,7 @@ static void intel_pmu_enable_event(struct perf_event *event) * must enabled before any actual event * because any event may be combined with LBR */ - if (intel_pmu_needs_lbr_smpl(event)) + if (needs_branch_stack(event)) intel_pmu_lbr_enable(event); if (event->attr.exclude_host) @@ -1747,7 +1733,7 @@ static int intel_pmu_hw_config(struct perf_event *event) if (event->attr.precise_ip && x86_pmu.pebs_aliases) x86_pmu.pebs_aliases(event); - if (intel_pmu_needs_lbr_smpl(event)) { + if (needs_branch_stack(event)) { ret = intel_pmu_setup_lbr_filter(event); if (ret) return ret; diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 270cd0173e61..43cc158487e6 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -814,6 +814,11 @@ static inline bool has_branch_stack(struct perf_event *event) return event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK; } +static inline bool needs_branch_stack(struct perf_event *event) +{ + return event->attr.branch_sample_type != 0; +} + extern int perf_output_begin(struct perf_output_handle *handle, struct perf_event *event, unsigned int size); extern void perf_output_end(struct perf_output_handle *handle); diff --git a/kernel/events/core.c b/kernel/events/core.c index 84451c0debba..257eccf9afd4 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7232,6 +7232,9 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) goto err_ns; + if (!has_branch_stack(event)) + event->attr.branch_sample_type = 0; + pmu = perf_init_event(event); if (!pmu) goto err_ns; -- cgit v1.2.3 From 2c44b1936bb3b135a3fac8b3493394d42e51cf70 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 5 Nov 2014 10:36:45 +0100 Subject: perf/x86/intel: Expose LBR callstack to user space tooling With LBR call stack feature enable, there are three callchain options. Enable the 3rd callchain option (LBR callstack) to user space tooling. Signed-off-by: Peter Zijlstra (Intel) Cc: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Andy Lutomirski Cc: Kan Liang Cc: Linus Torvalds Cc: Paul Mackerras Cc: Vince Weaver Cc: linux-api@vger.kernel.org Link: http://lkml.kernel.org/r/20141105093759.GQ10501@worktop.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.h | 8 -------- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 8 ++++---- include/uapi/linux/perf_event.h | 16 ++++++++-------- 3 files changed, 12 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 69c26b396cf4..a371d27d6795 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -523,14 +523,6 @@ struct x86_perf_task_context { int lbr_stack_state; }; -enum { - PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = PERF_SAMPLE_BRANCH_MAX_SHIFT, - PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE, - - PERF_SAMPLE_BRANCH_CALL_STACK = - 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT, -}; - #define x86_add_quirk(func_) \ do { \ static struct x86_pmu_quirk __quirk __initdata = { \ diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index 084f2eb20c8b..0473874109cb 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -537,7 +537,7 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event) u64 mask = 0, v; int i; - for (i = 0; i < PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE; i++) { + for (i = 0; i < PERF_SAMPLE_BRANCH_MAX_SHIFT; i++) { if (!(br_type & (1ULL << i))) continue; @@ -821,7 +821,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) /* * Map interface branch filters onto LBR filters */ -static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE] = { +static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, @@ -840,7 +840,7 @@ static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE] = { [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, }; -static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE] = { +static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, @@ -852,7 +852,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE] = { [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, }; -static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_SELECT_MAP_SIZE] = { +static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index e46b93279e3d..1e3cd07cf76e 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -166,6 +166,8 @@ enum perf_branch_sample_type_shift { PERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9, /* not in transaction */ PERF_SAMPLE_BRANCH_COND_SHIFT = 10, /* conditional branches */ + PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11, /* call/ret stack */ + PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ }; @@ -175,18 +177,16 @@ enum perf_branch_sample_type { PERF_SAMPLE_BRANCH_HV = 1U << PERF_SAMPLE_BRANCH_HV_SHIFT, PERF_SAMPLE_BRANCH_ANY = 1U << PERF_SAMPLE_BRANCH_ANY_SHIFT, - PERF_SAMPLE_BRANCH_ANY_CALL = - 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT, - PERF_SAMPLE_BRANCH_ANY_RETURN = - 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT, - PERF_SAMPLE_BRANCH_IND_CALL = - 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT, - PERF_SAMPLE_BRANCH_ABORT_TX = - 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT, + PERF_SAMPLE_BRANCH_ANY_CALL = 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT, + PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT, + PERF_SAMPLE_BRANCH_IND_CALL = 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT, + PERF_SAMPLE_BRANCH_ABORT_TX = 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT, PERF_SAMPLE_BRANCH_IN_TX = 1U << PERF_SAMPLE_BRANCH_IN_TX_SHIFT, PERF_SAMPLE_BRANCH_NO_TX = 1U << PERF_SAMPLE_BRANCH_NO_TX_SHIFT, PERF_SAMPLE_BRANCH_COND = 1U << PERF_SAMPLE_BRANCH_COND_SHIFT, + PERF_SAMPLE_BRANCH_CALL_STACK = 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT, + PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, }; -- cgit v1.2.3 From acba3c7e4652ca5fcb2fd9376d58c2dffd8ddf2a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 14 Jan 2015 14:15:39 +0100 Subject: perf, powerpc: Fix up flush_branch_stack() users The recent LBR rework for x86 left a stray flush_branch_stack() user in the PowerPC code, fix that up. Signed-off-by: Peter Zijlstra (Intel) Cc: Anshuman Khandual Cc: Anton Blanchard Cc: Arnaldo Carvalho de Melo Cc: Benjamin Herrenschmidt Cc: Christoph Lameter Cc: Joel Stanley Cc: Linus Torvalds Cc: Michael Ellerman Cc: Michael Neuling Cc: Paul Mackerras Cc: Tejun Heo Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Ingo Molnar --- arch/powerpc/perf/core-book3s.c | 13 +++++++++---- include/linux/perf_event.h | 5 ----- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 7c4f6690533a..7fd60dcb2cb0 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -124,7 +124,7 @@ static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw) static inline void power_pmu_bhrb_enable(struct perf_event *event) {} static inline void power_pmu_bhrb_disable(struct perf_event *event) {} -static void power_pmu_flush_branch_stack(void) {} +static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) {} static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {} static void pmao_restore_workaround(bool ebb) { } #endif /* CONFIG_PPC32 */ @@ -350,6 +350,7 @@ static void power_pmu_bhrb_enable(struct perf_event *event) cpuhw->bhrb_context = event->ctx; } cpuhw->bhrb_users++; + perf_sched_cb_inc(event->ctx->pmu); } static void power_pmu_bhrb_disable(struct perf_event *event) @@ -361,6 +362,7 @@ static void power_pmu_bhrb_disable(struct perf_event *event) cpuhw->bhrb_users--; WARN_ON_ONCE(cpuhw->bhrb_users < 0); + perf_sched_cb_dec(event->ctx->pmu); if (!cpuhw->disabled && !cpuhw->bhrb_users) { /* BHRB cannot be turned off when other @@ -375,9 +377,12 @@ static void power_pmu_bhrb_disable(struct perf_event *event) /* Called from ctxsw to prevent one process's branch entries to * mingle with the other process's entries during context switch. */ -static void power_pmu_flush_branch_stack(void) +static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) { - if (ppmu->bhrb_nr) + if (!ppmu->bhrb_nr) + return; + + if (sched_in) power_pmu_bhrb_reset(); } /* Calculate the to address for a branch */ @@ -1901,7 +1906,7 @@ static struct pmu power_pmu = { .cancel_txn = power_pmu_cancel_txn, .commit_txn = power_pmu_commit_txn, .event_idx = power_pmu_event_idx, - .flush_branch_stack = power_pmu_flush_branch_stack, + .sched_task = power_pmu_sched_task, }; /* diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 43cc158487e6..724d3720c9b1 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -261,11 +261,6 @@ struct pmu { */ int (*event_idx) (struct perf_event *event); /*optional */ - /* - * flush branch stack on context-switches (needed in cpu-wide mode) - */ - void (*flush_branch_stack) (void); - /* * context-switches callback */ -- cgit v1.2.3 From 4421f8f0fa02bc982b410cd773223cc280791c54 Mon Sep 17 00:00:00 2001 From: Miroslav Benes Date: Wed, 18 Feb 2015 15:21:07 +0100 Subject: livepatch: remove extern specifier from header files Storage-class specifier 'extern' is redundant in front of the function declaration. According to the C specification it has the same meaning as if not present at all. So remove it. Signed-off-by: Miroslav Benes Acked-by: Josh Poimboeuf Reviewed-by: Masami Hiramatsu Signed-off-by: Jiri Kosina --- arch/x86/include/asm/livepatch.h | 4 ++-- include/linux/livepatch.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h index a455a53d789a..2d29197bd2fb 100644 --- a/arch/x86/include/asm/livepatch.h +++ b/arch/x86/include/asm/livepatch.h @@ -32,8 +32,8 @@ static inline int klp_check_compiler_support(void) #endif return 0; } -extern int klp_write_module_reloc(struct module *mod, unsigned long type, - unsigned long loc, unsigned long value); +int klp_write_module_reloc(struct module *mod, unsigned long type, + unsigned long loc, unsigned long value); static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) { diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index 95023fd8b00d..ee6dbb39a809 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h @@ -123,10 +123,10 @@ struct klp_patch { enum klp_state state; }; -extern int klp_register_patch(struct klp_patch *); -extern int klp_unregister_patch(struct klp_patch *); -extern int klp_enable_patch(struct klp_patch *); -extern int klp_disable_patch(struct klp_patch *); +int klp_register_patch(struct klp_patch *); +int klp_unregister_patch(struct klp_patch *); +int klp_enable_patch(struct klp_patch *); +int klp_disable_patch(struct klp_patch *); #endif /* CONFIG_LIVEPATCH */ -- cgit v1.2.3 From db2dcb4f91d5fec5c346a82c309187ee821e2495 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 20 Jan 2015 13:00:46 +0000 Subject: irqflags: Fix (at least latent) code generation issue The conditional in local_irq_restore() otherwise can cause code bloat (the if and else blocks may get translated into separate code paths despite the generated code being identical, dependent on compiler internal heuristics). Note that this adjustment gets the code in sync with the comment preceding it (which was slightly wrong from at least from 2.6.37 onwards). The code bloat was observed in reality with an experimental x86 patch. Signed-off-by: Jan Beulich Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/54BE5F8E02000078000570A7@mail.emea.novell.com Signed-off-by: Ingo Molnar --- include/linux/irqflags.h | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index d176d658fe25..5dd1272d1ab2 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -85,7 +85,7 @@ * The local_irq_*() APIs are equal to the raw_local_irq*() * if !TRACE_IRQFLAGS. */ -#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT +#ifdef CONFIG_TRACE_IRQFLAGS #define local_irq_enable() \ do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0) #define local_irq_disable() \ @@ -107,22 +107,6 @@ raw_local_irq_restore(flags); \ } \ } while (0) -#define local_save_flags(flags) \ - do { \ - raw_local_save_flags(flags); \ - } while (0) - -#define irqs_disabled_flags(flags) \ - ({ \ - raw_irqs_disabled_flags(flags); \ - }) - -#define irqs_disabled() \ - ({ \ - unsigned long _flags; \ - raw_local_save_flags(_flags); \ - raw_irqs_disabled_flags(_flags); \ - }) #define safe_halt() \ do { \ @@ -131,7 +115,7 @@ } while (0) -#else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */ +#else /* !CONFIG_TRACE_IRQFLAGS */ #define local_irq_enable() do { raw_local_irq_enable(); } while (0) #define local_irq_disable() do { raw_local_irq_disable(); } while (0) @@ -140,11 +124,28 @@ raw_local_irq_save(flags); \ } while (0) #define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0) -#define local_save_flags(flags) do { raw_local_save_flags(flags); } while (0) -#define irqs_disabled() (raw_irqs_disabled()) -#define irqs_disabled_flags(flags) (raw_irqs_disabled_flags(flags)) #define safe_halt() do { raw_safe_halt(); } while (0) +#endif /* CONFIG_TRACE_IRQFLAGS */ + +#define local_save_flags(flags) raw_local_save_flags(flags) + +/* + * Some architectures don't define arch_irqs_disabled(), so even if either + * definition would be fine we need to use different ones for the time being + * to avoid build issues. + */ +#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT +#define irqs_disabled() \ + ({ \ + unsigned long _flags; \ + raw_local_save_flags(_flags); \ + raw_irqs_disabled_flags(_flags); \ + }) +#else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */ +#define irqs_disabled() raw_irqs_disabled() #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ +#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) + #endif -- cgit v1.2.3 From fba7ecf09bc458b15f9d578e4213c8c349f9592d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:55 +0200 Subject: Bluetooth: Convert hci_cb_list_lock to a mutex We'll soon need to be able to sleep inside the loops that iterate the hci_cb list, so neither a spinlock, rwlock or rcu are usable. This patch changes the lock to a mutex which permits sleeping while holding the lock. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 18 +++++++++--------- net/bluetooth/hci_core.c | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5f1ca3359c1a..137a18226975 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -499,7 +499,7 @@ struct hci_conn_params { extern struct list_head hci_dev_list; extern struct list_head hci_cb_list; extern rwlock_t hci_dev_list_lock; -extern rwlock_t hci_cb_list_lock; +extern struct mutex hci_cb_list_lock; /* ----- HCI interface to upper protocols ----- */ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); @@ -1160,12 +1160,12 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00; - read_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { if (cb->security_cfm) cb->security_cfm(conn, status, encrypt); } - read_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); } static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, @@ -1181,24 +1181,24 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, hci_proto_encrypt_cfm(conn, status, encrypt); - read_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { if (cb->security_cfm) cb->security_cfm(conn, status, encrypt); } - read_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); } static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status) { struct hci_cb *cb; - read_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { if (cb->key_change_cfm) cb->key_change_cfm(conn, status); } - read_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); } static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, @@ -1206,12 +1206,12 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, { struct hci_cb *cb; - read_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { if (cb->role_switch_cfm) cb->role_switch_cfm(conn, status, role); } - read_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); } static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 91f557b0318a..dbd26bcb9210 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -51,7 +51,7 @@ DEFINE_RWLOCK(hci_dev_list_lock); /* HCI callback list */ LIST_HEAD(hci_cb_list); -DEFINE_RWLOCK(hci_cb_list_lock); +DEFINE_MUTEX(hci_cb_list_lock); /* HCI ID Numbering */ static DEFINE_IDA(hci_index_ida); @@ -3464,9 +3464,9 @@ int hci_register_cb(struct hci_cb *cb) { BT_DBG("%p name %s", cb, cb->name); - write_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_add_tail(&cb->list, &hci_cb_list); - write_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); return 0; } @@ -3476,9 +3476,9 @@ int hci_unregister_cb(struct hci_cb *cb) { BT_DBG("%p name %s", cb, cb->name); - write_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_del(&cb->list); - write_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); return 0; } -- cgit v1.2.3 From 354fe804edb29625eee6dd7b1f3c72b43392704d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:56 +0200 Subject: Bluetooth: Convert L2CAP security callback to use hci_cb There's no reason to have the custom hci_proto_auth/encrypt_cfm helpers when the hci_cb list works equally well. This patch adds L2CAP to the hci_cb list and makes l2cap_security_cfm a private function of l2cap_core.c. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 40 ++++++---------------------------------- net/bluetooth/l2cap_core.c | 14 ++++++++++---- 2 files changed, 16 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 137a18226975..4a2db5e62699 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -506,7 +506,6 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); void l2cap_connect_cfm(struct hci_conn *hcon, u8 status); int l2cap_disconn_ind(struct hci_conn *hcon); void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason); -int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt); int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); @@ -1107,35 +1106,6 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) conn->disconn_cfm_cb(conn, reason); } -static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) -{ - __u8 encrypt; - - if (conn->type != ACL_LINK && conn->type != LE_LINK) - return; - - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) - return; - - encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00; - l2cap_security_cfm(conn, status, encrypt); - - if (conn->security_cfm_cb) - conn->security_cfm_cb(conn, status); -} - -static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, - __u8 encrypt) -{ - if (conn->type != ACL_LINK && conn->type != LE_LINK) - return; - - l2cap_security_cfm(conn, status, encrypt); - - if (conn->security_cfm_cb) - conn->security_cfm_cb(conn, status); -} - /* ----- HCI callbacks ----- */ struct hci_cb { struct list_head list; @@ -1153,8 +1123,6 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) struct hci_cb *cb; __u8 encrypt; - hci_proto_auth_cfm(conn, status); - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return; @@ -1166,6 +1134,9 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) cb->security_cfm(conn, status, encrypt); } mutex_unlock(&hci_cb_list_lock); + + if (conn->security_cfm_cb) + conn->security_cfm_cb(conn, status); } static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, @@ -1179,14 +1150,15 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, if (conn->pending_sec_level > conn->sec_level) conn->sec_level = conn->pending_sec_level; - hci_proto_encrypt_cfm(conn, status, encrypt); - mutex_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { if (cb->security_cfm) cb->security_cfm(conn, status, encrypt); } mutex_unlock(&hci_cb_list_lock); + + if (conn->security_cfm_cb) + conn->security_cfm_cb(conn, status); } static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ec6f78e481dc..424fcc5c4980 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7345,13 +7345,13 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) } } -int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) +static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan; if (!conn) - return 0; + return; BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt); @@ -7434,8 +7434,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } mutex_unlock(&conn->chan_lock); - - return 0; } int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) @@ -7543,6 +7541,11 @@ drop: return 0; } +static struct hci_cb l2cap_cb = { + .name = "L2CAP", + .security_cfm = l2cap_security_cfm, +}; + static int l2cap_debugfs_show(struct seq_file *f, void *p) { struct l2cap_chan *c; @@ -7584,6 +7587,8 @@ int __init l2cap_init(void) if (err < 0) return err; + hci_register_cb(&l2cap_cb); + if (IS_ERR_OR_NULL(bt_debugfs)) return 0; @@ -7601,6 +7606,7 @@ int __init l2cap_init(void) void l2cap_exit(void) { debugfs_remove(l2cap_debugfs); + hci_unregister_cb(&l2cap_cb); l2cap_cleanup_sockets(); } -- cgit v1.2.3 From 539c496d88f7f96d42abde4e9d901c8f8167d615 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:57 +0200 Subject: Bluetooth: Convert connect_cfm to be triggered through hci_cb This patch moves all the connect_cfm callbacks to be based on the hci_cb list. This means making l2cap_connect_cfm private to l2cap_core.c and sco_connect_cb private to sco.c respectively. Since the hci_conn type filtering isn't done any more on the wrapper level the callbacks themselves need to check that they were passed a relevant type of connection. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 40 ++++++++++++++++------------------------ net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_event.c | 36 ++++++++++++++++++------------------ net/bluetooth/l2cap_core.c | 6 +++++- net/bluetooth/sco.c | 15 ++++++++++++++- 5 files changed, 55 insertions(+), 46 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4a2db5e62699..0f00f0e9f257 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -503,13 +503,11 @@ extern struct mutex hci_cb_list_lock; /* ----- HCI interface to upper protocols ----- */ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); -void l2cap_connect_cfm(struct hci_conn *hcon, u8 status); int l2cap_disconn_ind(struct hci_conn *hcon); void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason); int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); -void sco_connect_cfm(struct hci_conn *hcon, __u8 status); void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); @@ -1050,28 +1048,6 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, } } -static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) -{ - switch (conn->type) { - case ACL_LINK: - case LE_LINK: - l2cap_connect_cfm(conn, status); - break; - - case SCO_LINK: - case ESCO_LINK: - sco_connect_cfm(conn, status); - break; - - default: - BT_ERR("unknown link type %d", conn->type); - break; - } - - if (conn->connect_cfm_cb) - conn->connect_cfm_cb(conn, status); -} - static inline int hci_proto_disconn_ind(struct hci_conn *conn) { if (conn->type != ACL_LINK && conn->type != LE_LINK) @@ -1112,12 +1088,28 @@ struct hci_cb { char *name; + void (*connect_cfm) (struct hci_conn *conn, __u8 status); void (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); void (*key_change_cfm) (struct hci_conn *conn, __u8 status); void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role); }; +static inline void hci_connect_cfm(struct hci_conn *conn, __u8 status) +{ + struct hci_cb *cb; + + mutex_lock(&hci_cb_list_lock); + list_for_each_entry(cb, &hci_cb_list, list) { + if (cb->connect_cfm) + cb->connect_cfm(conn, status); + } + mutex_unlock(&hci_cb_list_lock); + + if (conn->connect_cfm_cb) + conn->connect_cfm_cb(conn, status); +} + static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) { struct hci_cb *cb; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e3263b61bcf3..e9206734e024 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -309,7 +309,7 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) else hci_add_sco(sco, conn->handle); } else { - hci_proto_connect_cfm(sco, status); + hci_connect_cfm(sco, status); hci_conn_del(sco); } } @@ -618,7 +618,7 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, status); - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_del(conn); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a3fb094822b6..0b599129c64c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1537,7 +1537,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (conn && conn->state == BT_CONNECT) { if (status != 0x0c || conn->attempt > 2) { conn->state = BT_CLOSED; - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_del(conn); } else conn->state = BT_CONNECT2; @@ -1581,7 +1581,7 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status) if (sco) { sco->state = BT_CLOSED; - hci_proto_connect_cfm(sco, status); + hci_connect_cfm(sco, status); hci_conn_del(sco); } } @@ -1608,7 +1608,7 @@ static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1635,7 +1635,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1811,7 +1811,7 @@ static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1838,7 +1838,7 @@ static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1873,7 +1873,7 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) if (sco) { sco->state = BT_CLOSED; - hci_proto_connect_cfm(sco, status); + hci_connect_cfm(sco, status); hci_conn_del(sco); } } @@ -2255,10 +2255,10 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_sco_setup(conn, ev->status); if (ev->status) { - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_del(conn); } else if (ev->link_type != ACL_LINK) - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); unlock: hci_dev_unlock(hdev); @@ -2366,7 +2366,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) &cp); } else { conn->state = BT_CONNECT2; - hci_proto_connect_cfm(conn, 0); + hci_connect_cfm(conn, 0); } } @@ -2501,7 +2501,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) &cp); } else { conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } } else { @@ -2629,12 +2629,12 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && (!test_bit(HCI_CONN_AES_CCM, &conn->flags) || conn->key_type != HCI_LK_AUTH_COMBINATION_P256)) { - hci_proto_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE); + hci_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE); hci_conn_drop(conn); goto unlock; } - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } else hci_encrypt_cfm(conn, ev->status, ev->encrypt); @@ -2707,7 +2707,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } @@ -3679,7 +3679,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } @@ -3738,7 +3738,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, break; } - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); if (ev->status) hci_conn_del(conn); @@ -3849,7 +3849,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, if (!ev->status) conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } else { hci_auth_cfm(conn, ev->status); @@ -4512,7 +4512,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_debugfs_create_conn(conn); hci_conn_add_sysfs(conn); - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst, conn->dst_type); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 424fcc5c4980..6e2c3bdda7d3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7252,13 +7252,16 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, return NULL; } -void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) +static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) { struct hci_dev *hdev = hcon->hdev; struct l2cap_conn *conn; struct l2cap_chan *pchan; u8 dst_type; + if (hcon->type != ACL_LINK && hcon->type != LE_LINK) + return; + BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); if (status) { @@ -7543,6 +7546,7 @@ drop: static struct hci_cb l2cap_cb = { .name = "L2CAP", + .connect_cfm = l2cap_connect_cfm, .security_cfm = l2cap_security_cfm, }; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 76321b546e84..3c2e36f94b65 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -1083,9 +1083,13 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) return lm; } -void sco_connect_cfm(struct hci_conn *hcon, __u8 status) +static void sco_connect_cfm(struct hci_conn *hcon, __u8 status) { + if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) + return; + BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); + if (!status) { struct sco_conn *conn; @@ -1122,6 +1126,11 @@ drop: return 0; } +static struct hci_cb sco_cb = { + .name = "SCO", + .connect_cfm = sco_connect_cfm, +}; + static int sco_debugfs_show(struct seq_file *f, void *p) { struct sock *sk; @@ -1203,6 +1212,8 @@ int __init sco_init(void) BT_INFO("SCO socket layer initialized"); + hci_register_cb(&sco_cb); + if (IS_ERR_OR_NULL(bt_debugfs)) return 0; @@ -1222,6 +1233,8 @@ void __exit sco_exit(void) debugfs_remove(sco_debugfs); + hci_unregister_cb(&sco_cb); + bt_sock_unregister(BTPROTO_SCO); proto_unregister(&sco_proto); -- cgit v1.2.3 From 3a6d576be9fe02b0c3ffa89ef6eac048e14eec84 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:58 +0200 Subject: Bluetooth: Convert disconn_cfm to be triggered through hci_cb This patch moves all the disconn_cfm callbacks to be based on the hci_cb list. This means making l2cap_disconn_cfm private to l2cap_core.c and sco_conn_cb private to sco.c respectively. Since the hci_conn type filtering isn't done any more on the wrapper level the callbacks themselves need to check that they were passed a relevant type of connection. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 44 +++++++++++++++------------------------- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/hci_event.c | 2 +- net/bluetooth/l2cap_core.c | 6 +++++- net/bluetooth/sco.c | 6 +++++- 5 files changed, 28 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0f00f0e9f257..a7bf77384464 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -504,11 +504,9 @@ extern struct mutex hci_cb_list_lock; /* ----- HCI interface to upper protocols ----- */ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); int l2cap_disconn_ind(struct hci_conn *hcon); -void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason); int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); -void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); /* ----- Inquiry cache ----- */ @@ -1056,32 +1054,6 @@ static inline int hci_proto_disconn_ind(struct hci_conn *conn) return l2cap_disconn_ind(conn); } -static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) -{ - switch (conn->type) { - case ACL_LINK: - case LE_LINK: - l2cap_disconn_cfm(conn, reason); - break; - - case SCO_LINK: - case ESCO_LINK: - sco_disconn_cfm(conn, reason); - break; - - /* L2CAP would be handled for BREDR chan */ - case AMP_LINK: - break; - - default: - BT_ERR("unknown link type %d", conn->type); - break; - } - - if (conn->disconn_cfm_cb) - conn->disconn_cfm_cb(conn, reason); -} - /* ----- HCI callbacks ----- */ struct hci_cb { struct list_head list; @@ -1089,6 +1061,7 @@ struct hci_cb { char *name; void (*connect_cfm) (struct hci_conn *conn, __u8 status); + void (*disconn_cfm) (struct hci_conn *conn, __u8 status); void (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); void (*key_change_cfm) (struct hci_conn *conn, __u8 status); @@ -1110,6 +1083,21 @@ static inline void hci_connect_cfm(struct hci_conn *conn, __u8 status) conn->connect_cfm_cb(conn, status); } +static inline void hci_disconn_cfm(struct hci_conn *conn, __u8 reason) +{ + struct hci_cb *cb; + + mutex_lock(&hci_cb_list_lock); + list_for_each_entry(cb, &hci_cb_list, list) { + if (cb->disconn_cfm) + cb->disconn_cfm(conn, reason); + } + mutex_unlock(&hci_cb_list_lock); + + if (conn->disconn_cfm_cb) + conn->disconn_cfm_cb(conn, reason); +} + static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) { struct hci_cb *cb; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e9206734e024..91ebb9cb31de 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1151,7 +1151,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev) list_for_each_entry_safe(c, n, &h->list, list) { c->state = BT_CLOSED; - hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); + hci_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); hci_conn_del(c); } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0b599129c64c..e9b17b585ee8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2444,7 +2444,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) type = conn->type; - hci_proto_disconn_cfm(conn, ev->reason); + hci_disconn_cfm(conn, ev->reason); hci_conn_del(conn); /* Re-enable advertising if necessary, since it might diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6e2c3bdda7d3..91c682846bcf 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7324,8 +7324,11 @@ int l2cap_disconn_ind(struct hci_conn *hcon) return conn->disc_reason; } -void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) +static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) { + if (hcon->type != ACL_LINK && hcon->type != LE_LINK) + return; + BT_DBG("hcon %p reason %d", hcon, reason); l2cap_conn_del(hcon, bt_to_errno(reason)); @@ -7547,6 +7550,7 @@ drop: static struct hci_cb l2cap_cb = { .name = "L2CAP", .connect_cfm = l2cap_connect_cfm, + .disconn_cfm = l2cap_disconn_cfm, .security_cfm = l2cap_security_cfm, }; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 3c2e36f94b65..b94c3151896e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -1100,8 +1100,11 @@ static void sco_connect_cfm(struct hci_conn *hcon, __u8 status) sco_conn_del(hcon, bt_to_errno(status)); } -void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) +static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) { + if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) + return; + BT_DBG("hcon %p reason %d", hcon, reason); sco_conn_del(hcon, bt_to_errno(reason)); @@ -1129,6 +1132,7 @@ drop: static struct hci_cb sco_cb = { .name = "SCO", .connect_cfm = sco_connect_cfm, + .disconn_cfm = sco_disconn_cfm, }; static int sco_debugfs_show(struct seq_file *f, void *p) -- cgit v1.2.3 From 229d043096ea8e58829d37d35767afeac15997f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:03 -0600 Subject: ALSA: core: selection of audio_tstamp type and accuracy reports Audio timestamps can be extracted from sample counters, wall clocks, PHC clocks (Ethernet AVB), on-demand synchronized snapshots. This patch provides the ability to report timestamping capabilities, select timestamp types and retrieve timestamp accuracy, if supported. Details can be found in Documentations/sound/alsa/timestamping.txt This functionality is introduced by reclaiming the reserved_aligned field introduced by commit9c7066aef4a5eb8e4063de28f06c508bf6f2963a in snd_pcm_status to provide userspace with selection/query capabilities. Additional driver_tstamp and audio_tstamp_accuracy fields are also added. snd_pcm_mmap_status remains a read-only structure with only the audio timestamp value accessible from user space. The selection of audio timestamp type is done through snd_pcm_status only This commit does not impact ABI and does not impact the default behavior. By default audio timestamp is aligned with hw_pointer and reports the DMA position. Backwards compatibility is handled by using the HDAudio wall clock for playback and the hw_ptr for all other cases. For timestamp selection a new STATUS_EXT ioctl is introduced with read/write parameters. Alsa-lib will be modified to make use of STATUS_EXT. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/timestamping.txt | 200 ++++++++++++++++++++++++++++++ include/sound/pcm.h | 60 +++++++++ include/uapi/sound/asound.h | 34 ++++- 3 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 Documentation/sound/alsa/timestamping.txt (limited to 'include') diff --git a/Documentation/sound/alsa/timestamping.txt b/Documentation/sound/alsa/timestamping.txt new file mode 100644 index 000000000000..0b191a23f534 --- /dev/null +++ b/Documentation/sound/alsa/timestamping.txt @@ -0,0 +1,200 @@ +The ALSA API can provide two different system timestamps: + +- Trigger_tstamp is the system time snapshot taken when the .trigger +callback is invoked. This snapshot is taken by the ALSA core in the +general case, but specific hardware may have synchronization +capabilities or conversely may only be able to provide a correct +estimate with a delay. In the latter two cases, the low-level driver +is responsible for updating the trigger_tstamp at the most appropriate +and precise moment. Applications should not rely solely on the first +trigger_tstamp but update their internal calculations if the driver +provides a refined estimate with a delay. + +- tstamp is the current system timestamp updated during the last +event or application query. +The difference (tstamp - trigger_tstamp) defines the elapsed time. + +The ALSA API provides reports two basic pieces of information, avail +and delay, which combined with the trigger and current system +timestamps allow for applications to keep track of the 'fullness' of +the ring buffer and the amount of queued samples. + +The use of these different pointers and time information depends on +the application needs: + +- 'avail' reports how much can be written in the ring buffer +- 'delay' reports the time it will take to hear a new sample after all +queued samples have been played out. + +When timestamps are enabled, the avail/delay information is reported +along with a snapshot of system time. Applications can select from +CLOCK_REALTIME (NTP corrections including going backwards), +CLOCK_MONOTONIC (NTP corrections but never going backwards), +CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode +dynamically with sw_params + + +The ALSA API also provide an audio_tstamp which reflects the passage +of time as measured by different components of audio hardware. In +ascii-art, this could be represented as follows (for the playback +case): + + +--------------------------------------------------------------> time + ^ ^ ^ ^ ^ + | | | | | + analog link dma app FullBuffer + time time time time time + | | | | | + |< codec delay >|<--hw delay-->||<---avail->| + |<----------------- delay---------------------->| | + |<----ring buffer length---->| + +The analog time is taken at the last stage of the playback, as close +as possible to the actual transducer + +The link time is taken at the output of the SOC/chipset as the samples +are pushed on a link. The link time can be directly measured if +supported in hardware by sample counters or wallclocks (e.g. with +HDAudio 24MHz or PTP clock for networked solutions) or indirectly +estimated (e.g. with the frame counter in USB). + +The DMA time is measured using counters - typically the least reliable +of all measurements due to the bursty natured of DMA transfers. + +The app time corresponds to the time tracked by an application after +writing in the ring buffer. + +The application can query what the hardware supports, define which +audio time it wants reported by selecting the relevant settings in +audio_tstamp_config fields, get an estimate of the timestamp +accuracy. It can also request the delay-to-analog be included in the +measurement. Direct access to the link time is very interesting on +platforms that provide an embedded DSP; measuring directly the link +time with dedicated hardware, possibly synchronized with system time, +removes the need to keep track of internal DSP processing times and +latency. + +In case the application requests an audio tstamp that is not supported +in hardware/low-level driver, the type is overridden as DEFAULT and the +timestamp will report the DMA time based on the hw_pointer value. + +For backwards compatibility with previous implementations that did not +provide timestamp selection, with a zero-valued COMPAT timestamp type +the results will default to the HDAudio wall clock for playback +streams and to the DMA time (hw_ptr) in all other cases. + +The audio timestamp accuracy can be returned to user-space, so that +appropriate decisions are made: + +- for dma time (default), the granularity of the transfers can be + inferred from the steps between updates and in turn provide + information on how much the application pointer can be rewound + safely. + +- the link time can be used to track long-term drifts between audio + and system time using the (tstamp-trigger_tstamp)/audio_tstamp + ratio, the precision helps define how much smoothing/low-pass + filtering is required. The link time can be either reset on startup + or reported as is (the latter being useful to compare progress of + different streams - but may require the wallclock to be always + running and not wrap-around during idle periods). If supported in + hardware, the absolute link time could also be used to define a + precise start time (patches WIP) + +- including the delay in the audio timestamp may + counter-intuitively not increase the precision of timestamps, e.g. if a + codec includes variable-latency DSP processing or a chain of + hardware components the delay is typically not known with precision. + +The accuracy is reported in nanosecond units (using an unsigned 32-bit +word), which gives a max precision of 4.29s, more than enough for +audio applications... + +Due to the varied nature of timestamping needs, even for a single +application, the audio_tstamp_config can be changed dynamically. In +the STATUS ioctl, the parameters are read-only and do not allow for +any application selection. To work around this limitation without +impacting legacy applications, a new STATUS_EXT ioctl is introduced +with read/write parameters. ALSA-lib will be modified to make use of +STATUS_EXT and effectively deprecate STATUS. + +The ALSA API only allows for a single audio timestamp to be reported +at a time. This is a conscious design decision, reading the audio +timestamps from hardware registers or from IPC takes time, the more +timestamps are read the more imprecise the combined measurements +are. To avoid any interpretation issues, a single (system, audio) +timestamp is reported. Applications that need different timestamps +will be required to issue multiple queries and perform an +interpolation of the results + +In some hardware-specific configuration, the system timestamp is +latched by a low-level audio subsytem, and the information provided +back to the driver. Due to potential delays in the communication with +the hardware, there is a risk of misalignment with the avail and delay +information. To make sure applications are not confused, a +driver_timestamp field is added in the snd_pcm_status structure; this +timestamp shows when the information is put together by the driver +before returning from the STATUS and STATUS_EXT ioctl. in most cases +this driver_timestamp will be identical to the regular system tstamp. + +Examples of typestamping with HDaudio: + +1. DMA timestamp, no compensation for DMA+analog delay +$ ./audio_time -p --ts_type=1 +playback: systime: 341121338 nsec, audio time 342000000 nsec, systime delta -878662 +playback: systime: 426236663 nsec, audio time 427187500 nsec, systime delta -950837 +playback: systime: 597080580 nsec, audio time 598000000 nsec, systime delta -919420 +playback: systime: 682059782 nsec, audio time 683020833 nsec, systime delta -961051 +playback: systime: 852896415 nsec, audio time 853854166 nsec, systime delta -957751 +playback: systime: 937903344 nsec, audio time 938854166 nsec, systime delta -950822 + +2. DMA timestamp, compensation for DMA+analog delay +$ ./audio_time -p --ts_type=1 -d +playback: systime: 341053347 nsec, audio time 341062500 nsec, systime delta -9153 +playback: systime: 426072447 nsec, audio time 426062500 nsec, systime delta 9947 +playback: systime: 596899518 nsec, audio time 596895833 nsec, systime delta 3685 +playback: systime: 681915317 nsec, audio time 681916666 nsec, systime delta -1349 +playback: systime: 852741306 nsec, audio time 852750000 nsec, systime delta -8694 + +3. link timestamp, compensation for DMA+analog delay +$ ./audio_time -p --ts_type=2 -d +playback: systime: 341060004 nsec, audio time 341062791 nsec, systime delta -2787 +playback: systime: 426242074 nsec, audio time 426244875 nsec, systime delta -2801 +playback: systime: 597080992 nsec, audio time 597084583 nsec, systime delta -3591 +playback: systime: 682084512 nsec, audio time 682088291 nsec, systime delta -3779 +playback: systime: 852936229 nsec, audio time 852940916 nsec, systime delta -4687 +playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -5146 + +Example 1 shows that the timestamp at the DMA level is close to 1ms +ahead of the actual playback time (as a side time this sort of +measurement can help define rewind safeguards). Compensating for the +DMA-link delay in example 2 helps remove the hardware buffering abut +the information is still very jittery, with up to one sample of +error. In example 3 where the timestamps are measured with the link +wallclock, the timestamps show a monotonic behavior and a lower +dispersion. + +Example 3 and 4 are with USB audio class. Example 3 shows a high +offset between audio time and system time due to buffering. Example 4 +shows how compensating for the delay exposes a 1ms accuracy (due to +the use of the frame counter by the driver) + +Example 3: DMA timestamp, no compensation for delay, delta of ~5ms +$ ./audio_time -p -Dhw:1 -t1 +playback: systime: 120174019 nsec, audio time 125000000 nsec, systime delta -4825981 +playback: systime: 245041136 nsec, audio time 250000000 nsec, systime delta -4958864 +playback: systime: 370106088 nsec, audio time 375000000 nsec, systime delta -4893912 +playback: systime: 495040065 nsec, audio time 500000000 nsec, systime delta -4959935 +playback: systime: 620038179 nsec, audio time 625000000 nsec, systime delta -4961821 +playback: systime: 745087741 nsec, audio time 750000000 nsec, systime delta -4912259 +playback: systime: 870037336 nsec, audio time 875000000 nsec, systime delta -4962664 + +Example 4: DMA timestamp, compensation for delay, delay of ~1ms +$ ./audio_time -p -Dhw:1 -t1 -d +playback: systime: 120190520 nsec, audio time 120000000 nsec, systime delta 190520 +playback: systime: 245036740 nsec, audio time 244000000 nsec, systime delta 1036740 +playback: systime: 370034081 nsec, audio time 369000000 nsec, systime delta 1034081 +playback: systime: 495159907 nsec, audio time 494000000 nsec, systime delta 1159907 +playback: systime: 620098824 nsec, audio time 619000000 nsec, systime delta 1098824 +playback: systime: 745031847 nsec, audio time 744000000 nsec, systime delta 1031847 diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c0ddb7e69c28..60f0e48f7905 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -60,6 +60,9 @@ struct snd_pcm_hardware { struct snd_pcm_substream; +struct snd_pcm_audio_tstamp_config; /* definitions further down */ +struct snd_pcm_audio_tstamp_report; + struct snd_pcm_ops { int (*open)(struct snd_pcm_substream *substream); int (*close)(struct snd_pcm_substream *substream); @@ -281,6 +284,58 @@ struct snd_pcm_hw_constraint_ranges { struct snd_pcm_hwptr_log; +/* + * userspace-provided audio timestamp config to kernel, + * structure is for internal use only and filled with dedicated unpack routine + */ +struct snd_pcm_audio_tstamp_config { + /* 5 of max 16 bits used */ + u32 type_requested:4; + u32 report_delay:1; /* add total delay to A/D or D/A */ +}; + +static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data, + struct snd_pcm_audio_tstamp_config *config) +{ + config->type_requested = data & 0xF; + config->report_delay = (data >> 4) & 1; +} + +/* + * kernel-provided audio timestamp report to user-space + * structure is for internal use only and read by dedicated pack routine + */ +struct snd_pcm_audio_tstamp_report { + /* 6 of max 16 bits used for bit-fields */ + + /* for backwards compatibility */ + u32 valid:1; + + /* actual type if hardware could not support requested timestamp */ + u32 actual_type:4; + + /* accuracy represented in ns units */ + u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */ + u32 accuracy; /* up to 4.29s, will be packed in separate field */ +}; + +static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy, + const struct snd_pcm_audio_tstamp_report *report) +{ + u32 tmp; + + tmp = report->accuracy_report; + tmp <<= 4; + tmp |= report->actual_type; + tmp <<= 1; + tmp |= report->valid; + + *data &= 0xffff; /* zero-clear MSBs */ + *data |= (tmp << 16); + *accuracy = report->accuracy; +} + + struct snd_pcm_runtime { /* -- Status -- */ struct snd_pcm_substream *trigger_master; @@ -361,6 +416,11 @@ struct snd_pcm_runtime { struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */ + /* -- audio timestamp config -- */ + struct snd_pcm_audio_tstamp_config audio_tstamp_config; + struct snd_pcm_audio_tstamp_report audio_tstamp_report; + struct timespec driver_tstamp; + #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ struct snd_pcm_oss_runtime oss; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 0e88e7a0f0eb..acef4e4d2735 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -267,10 +267,17 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ -#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */ +#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */ + #define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ + + typedef int __bitwise snd_pcm_state_t; #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ #define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */ @@ -408,6 +415,22 @@ struct snd_pcm_channel_info { unsigned int step; /* samples distance in bits */ }; +enum { + /* + * first definition for backwards compatibility only, + * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else + */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, + + /* timestamp definitions */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED +}; + struct snd_pcm_status { snd_pcm_state_t state; /* stream state */ struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ @@ -419,9 +442,11 @@ struct snd_pcm_status { snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */ snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ snd_pcm_state_t suspended_state; /* suspended stream state */ - __u32 reserved_alignment; /* must be filled with zero */ - struct timespec audio_tstamp; /* from sample counter or wall clock */ - unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */ + __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */ + struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */ + struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */ + __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ + unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ }; struct snd_pcm_mmap_status { @@ -534,6 +559,7 @@ enum { #define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) #define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) #define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) #define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) #define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) #define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) -- cgit v1.2.3 From 3179f62001880e588e229db3006a59ad87b7792a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:06 -0600 Subject: ALSA: core: add .get_time_info Introduce more generic .get_time_info to retrieve system timestamp and audio timestamp in single routine. Backwards compatibility is preserved with same functionality as with .wall_clock method (to be removed in following commits to avoid breaking git bisect) Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 4 +++ sound/core/pcm_lib.c | 88 +++++++++++++++++++++++++++++++++---------------- sound/core/pcm_native.c | 24 ++++++++++++++ 3 files changed, 87 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 60f0e48f7905..04f2d492ae57 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -76,6 +76,10 @@ struct snd_pcm_ops { snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream); int (*wall_clock)(struct snd_pcm_substream *substream, struct timespec *audio_ts); + int (*get_time_info)(struct snd_pcm_substream *substream, + struct timespec *system_ts, struct timespec *audio_ts, + struct snd_pcm_audio_tstamp_config *audio_tstamp_config, + struct snd_pcm_audio_tstamp_report *audio_tstamp_report); int (*copy)(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void __user *buf, snd_pcm_uframes_t count); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ffd656012ab8..ac6b33f3779c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return 0; } +static void update_audio_tstamp(struct snd_pcm_substream *substream, + struct timespec *curr_tstamp, + struct timespec *audio_tstamp) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + u64 audio_frames, audio_nsecs; + struct timespec driver_tstamp; + + if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE) + return; + + if (!(substream->ops->get_time_info) || + (runtime->audio_tstamp_report.actual_type == + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) { + + /* + * provide audio timestamp derived from pointer position + * add delay only if requested + */ + + audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr; + + if (runtime->audio_tstamp_config.report_delay) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + audio_frames -= runtime->delay; + else + audio_frames += runtime->delay; + } + audio_nsecs = div_u64(audio_frames * 1000000000LL, + runtime->rate); + *audio_tstamp = ns_to_timespec(audio_nsecs); + } + runtime->status->audio_tstamp = *audio_tstamp; + runtime->status->tstamp = *curr_tstamp; + + /* + * re-take a driver timestamp to let apps detect if the reference tstamp + * read by low-level hardware was provided with a delay + */ + snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp); + runtime->driver_tstamp = driver_tstamp; +} + static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, unsigned int in_interrupt) { @@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, pos = substream->ops->pointer(substream); curr_jiffies = jiffies; if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { - snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); - - if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) && - (substream->ops->wall_clock)) - substream->ops->wall_clock(substream, &audio_tstamp); + if ((substream->ops->get_time_info) && + (runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) { + substream->ops->get_time_info(substream, &curr_tstamp, + &audio_tstamp, + &runtime->audio_tstamp_config, + &runtime->audio_tstamp_report); + + /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */ + if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT) + snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); + } else + snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); } if (pos == SNDRV_PCM_POS_XRUN) { @@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } no_delta_check: - if (runtime->status->hw_ptr == new_hw_ptr) + if (runtime->status->hw_ptr == new_hw_ptr) { + update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); return 0; + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) @@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, snd_BUG_ON(crossed_boundary != 1); runtime->hw_ptr_wrap += runtime->boundary; } - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { - runtime->status->tstamp = curr_tstamp; - if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) { - /* - * no wall clock available, provide audio timestamp - * derived from pointer position+delay - */ - u64 audio_frames, audio_nsecs; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - audio_frames = runtime->hw_ptr_wrap - + runtime->status->hw_ptr - - runtime->delay; - else - audio_frames = runtime->hw_ptr_wrap - + runtime->status->hw_ptr - + runtime->delay; - audio_nsecs = div_u64(audio_frames * 1000000000LL, - runtime->rate); - audio_tstamp = ns_to_timespec(audio_nsecs); - } - runtime->status->audio_tstamp = audio_tstamp; - } + update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); return snd_pcm_update_state(substream, runtime); } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 72323a8c35c8..9c2c6f801fed 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_stream_lock_irq(substream); + + snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data, + &runtime->audio_tstamp_config); + + /* backwards compatible behavior */ + if (runtime->audio_tstamp_config.type_requested == + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) { + if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) + runtime->audio_tstamp_config.type_requested = + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; + else + runtime->audio_tstamp_config.type_requested = + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; + runtime->audio_tstamp_report.valid = 0; + } else + runtime->audio_tstamp_report.valid = 1; + status->state = runtime->status->state; status->suspended_state = runtime->status->suspended_state; if (status->state == SNDRV_PCM_STATE_OPEN) @@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream, snd_pcm_update_hw_ptr(substream); if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { status->tstamp = runtime->status->tstamp; + status->driver_tstamp = runtime->driver_tstamp; status->audio_tstamp = runtime->status->audio_tstamp; + if (runtime->audio_tstamp_report.valid == 1) + /* backwards compatibility, no report provided in COMPAT mode */ + snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data, + &status->audio_tstamp_accuracy, + &runtime->audio_tstamp_report); + goto _tstamp_end; } } else { -- cgit v1.2.3 From 2d52a5abd5be35340296a251092c8a594679df54 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:08 -0600 Subject: ALSA: core: remove .wall_clock can be removed without breaking git-bisect now Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 04f2d492ae57..0cb7f3f5df7b 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -74,8 +74,6 @@ struct snd_pcm_ops { int (*prepare)(struct snd_pcm_substream *substream); int (*trigger)(struct snd_pcm_substream *substream, int cmd); snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream); - int (*wall_clock)(struct snd_pcm_substream *substream, - struct timespec *audio_ts); int (*get_time_info)(struct snd_pcm_substream *substream, struct timespec *system_ts, struct timespec *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, -- cgit v1.2.3 From c72638bdaabe9ea4b09003b9db7e1754f472fbed Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:09 -0600 Subject: ALSA: bump PCM protocol to 2.0.13 Bump PCM protocol to enable use of STATUS_EXT ioctls, older apps will still use STATUS and audio timestamp configuration is not supported (backwards compatible behavior). Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index acef4e4d2735..3d46e9a0cd2e 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -140,7 +140,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 12) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; -- cgit v1.2.3 From 7129069e84056ba28954550beb208b2645863299 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 20 Feb 2015 13:26:23 +0200 Subject: Bluetooth: Rename hci_send_to_control to hci_send_to_channel The hci_send_to_control() can be made more general purpose with a small change of passing the desired HCI channel as a parameter to it. This allows using it for the monitor channel as well as e.g. 6lowpan in the future. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_sock.c | 9 +++++---- net/bluetooth/mgmt.c | 3 ++- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a7bf77384464..a831c8ad10f1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1265,7 +1265,8 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); -void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); +void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, + struct sock *skip_sk); void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); void hci_sock_dev_event(struct hci_dev *hdev, int event); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1d65c5be7c82..ba5d45f8aac1 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -183,12 +183,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb_copy); } -/* Send frame to control socket */ -void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) +/* Send frame to sockets with specific channel */ +void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, + struct sock *skip_sk) { struct sock *sk; - BT_DBG("len %d", skb->len); + BT_DBG("channel %u len %d", channel, skb->len); read_lock(&hci_sk_list.lock); @@ -202,7 +203,7 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) if (sk->sk_state != BT_BOUND) continue; - if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL) + if (hci_pi(sk)->channel != channel) continue; nskb = skb_clone(skb, GFP_ATOMIC); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3a1b537c9aa6..d5d46e7676f1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -242,7 +243,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, /* Time stamp */ __net_timestamp(skb); - hci_send_to_control(skb, skip_sk); + hci_send_to_channel(HCI_CHANNEL_CONTROL, skb, skip_sk); kfree_skb(skb); return 0; -- cgit v1.2.3 From 959d10f6bbf6ab5b8813c4e37540a2e43ca2ae96 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Feb 2015 03:19:24 -0800 Subject: igmp: add __ip_mc_{join|leave}_group() There is a need to perform igmp join/leave operations while RTNL is held. Make ip_mc_{join|leave}_group() wrappers around __ip_mc_{join|leave}_group() to avoid the proliferation of work queues. For example, vxlan_igmp_join() could possibly be removed. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 ++ net/ipv4/igmp.c | 52 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 2c677afeea47..b5a6470e686c 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -111,7 +111,9 @@ struct ip_mc_list { extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u16 proto); extern int igmp_rcv(struct sk_buff *); +extern int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); +extern int __ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); extern void ip_mc_drop_socket(struct sock *sk); extern int ip_mc_source(int add, int omode, struct sock *sk, diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 666cf364df86..4b1172d73e03 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1849,30 +1849,25 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc) pmc->sfcount[MCAST_EXCLUDE] = 1; } - -/* - * Join a multicast group - */ -int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) +int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr) { - int err; __be32 addr = imr->imr_multiaddr.s_addr; - struct ip_mc_socklist *iml = NULL, *i; + struct ip_mc_socklist *iml, *i; struct in_device *in_dev; struct inet_sock *inet = inet_sk(sk); struct net *net = sock_net(sk); int ifindex; int count = 0; + int err; + + ASSERT_RTNL(); if (!ipv4_is_multicast(addr)) return -EINVAL; - rtnl_lock(); - in_dev = ip_mc_find_dev(net, imr); if (!in_dev) { - iml = NULL; err = -ENODEV; goto done; } @@ -1900,9 +1895,22 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) ip_mc_inc_group(in_dev, addr); err = 0; done: - rtnl_unlock(); return err; } +EXPORT_SYMBOL(__ip_mc_join_group); + +/* Join a multicast group + */ +int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr) +{ + int ret; + + rtnl_lock(); + ret = __ip_mc_join_group(sk, imr); + rtnl_unlock(); + + return ret; +} EXPORT_SYMBOL(ip_mc_join_group); static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, @@ -1925,11 +1933,7 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, return err; } -/* - * Ask a socket to leave a group. - */ - -int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) +int __ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) { struct inet_sock *inet = inet_sk(sk); struct ip_mc_socklist *iml; @@ -1940,7 +1944,8 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) u32 ifindex; int ret = -EADDRNOTAVAIL; - rtnl_lock(); + ASSERT_RTNL(); + in_dev = ip_mc_find_dev(net, imr); if (!in_dev) { ret = -ENODEV; @@ -1964,14 +1969,25 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) *imlp = iml->next_rcu; ip_mc_dec_group(in_dev, group); - rtnl_unlock(); + /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); kfree_rcu(iml, rcu); return 0; } out: + return ret; +} +EXPORT_SYMBOL(__ip_mc_leave_group); + +int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) +{ + int ret; + + rtnl_lock(); + ret = __ip_mc_leave_group(sk, imr); rtnl_unlock(); + return ret; } EXPORT_SYMBOL(ip_mc_leave_group); -- cgit v1.2.3 From 846cd66788b11105a62785078360c8854aa98310 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Feb 2015 11:38:06 +0100 Subject: net: Initialize all members in skb_gro_remcsum_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit skb_gro_remcsum_init() initializes the gro_remcsum.delta member only, leading to compiler warnings about a possibly uninitialized gro_remcsum.offset member: drivers/net/vxlan.c: In function ‘vxlan_gro_receive’: drivers/net/vxlan.c:602: warning: ‘grc.offset’ may be used uninitialized in this function net/ipv4/fou.c: In function ‘gue_gro_receive’: net/ipv4/fou.c:262: warning: ‘grc.offset’ may be used uninitialized in this function While these are harmless for now: - skb_gro_remcsum_process() sets offset before changing delta, - skb_gro_remcsum_cleanup() checks if delta is non-zero before accessing offset, it's safer to let the initialization function initialize all members. Signed-off-by: Geert Uytterhoeven Acked-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5897b4ea5a3f..429d1790a27e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2342,6 +2342,7 @@ struct gro_remcsum { static inline void skb_gro_remcsum_init(struct gro_remcsum *grc) { + grc->offset = 0; grc->delta = 0; } -- cgit v1.2.3 From 278f7b4fffce9ad267406cf8800df271d14f4a16 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 19 Feb 2015 12:13:13 +0300 Subject: caif: fix a signedness bug in cfpkt_iterate() The cfpkt_iterate() function can return -EPROTO on error, but the function is a u16 so the negative value gets truncated to a positive unsigned short. This causes a static checker warning. The only caller which might care is cffrml_receive(), when it's checking the frame checksum. I modified cffrml_receive() so that it never says -EPROTO is a valid checksum. Also this isn't ever going to be inlined so I removed the "inline". Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- include/net/caif/cfpkt.h | 2 +- net/caif/cffrml.c | 2 +- net/caif/cfpkt_skbuff.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h index 1c1ad46250d5..fe328c52c46b 100644 --- a/include/net/caif/cfpkt.h +++ b/include/net/caif/cfpkt.h @@ -171,7 +171,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos); * @return Checksum of buffer. */ -u16 cfpkt_iterate(struct cfpkt *pkt, +int cfpkt_iterate(struct cfpkt *pkt, u16 (*iter_func)(u16 chks, void *buf, u16 len), u16 data); diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index 8bc7caa28e64..434ba8557826 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -84,7 +84,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) u16 tmp; u16 len; u16 hdrchks; - u16 pktchks; + int pktchks; struct cffrml *this; this = container_obj(layr); diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c index 1be0b521ac49..f6c3b2137eea 100644 --- a/net/caif/cfpkt_skbuff.c +++ b/net/caif/cfpkt_skbuff.c @@ -255,9 +255,9 @@ inline u16 cfpkt_getlen(struct cfpkt *pkt) return skb->len; } -inline u16 cfpkt_iterate(struct cfpkt *pkt, - u16 (*iter_func)(u16, void *, u16), - u16 data) +int cfpkt_iterate(struct cfpkt *pkt, + u16 (*iter_func)(u16, void *, u16), + u16 data) { /* * Don't care about the performance hit of linearizing, -- cgit v1.2.3 From b9ebafbe8cfeeddec881504c446cccd0d87a51b6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 20 Feb 2015 06:48:57 -0800 Subject: rhashtable: ensure cache line alignment on bucket_table struct bucket_table contains mostly read fields : size, locks_mask, locks. Make sure these are not sharing a cache line with buckets[] Signed-off-by: Eric Dumazet Acked-by: Daniel Borkmann Acked-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rhashtable.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h index 58851275fed9..cb2104be2135 100644 --- a/include/linux/rhashtable.h +++ b/include/linux/rhashtable.h @@ -54,10 +54,11 @@ struct rhash_head { * @buckets: size * hash buckets */ struct bucket_table { - size_t size; - unsigned int locks_mask; - spinlock_t *locks; - struct rhash_head __rcu *buckets[]; + size_t size; + unsigned int locks_mask; + spinlock_t *locks; + + struct rhash_head __rcu *buckets[] ____cacheline_aligned_in_smp; }; typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed); -- cgit v1.2.3 From 059a2440fd3cf4ec57735db2c0a90401cde84fca Mon Sep 17 00:00:00 2001 From: Bojan Prtvar Date: Sun, 22 Feb 2015 11:46:35 +0100 Subject: net: Remove state argument from skb_find_text() Although it is clear that textsearch state is intentionally passed to skb_find_text() as uninitialized argument, it was never used by the callers. Therefore, we can simplify skb_find_text() by making it local variable. Signed-off-by: Bojan Prtvar Signed-off-by: David S. Miller --- include/linux/skbuff.h | 3 +-- net/core/skbuff.c | 9 ++++----- net/netfilter/nf_conntrack_amanda.c | 10 +++------- net/netfilter/xt_string.c | 3 +-- net/sched/em_text.c | 3 +-- 5 files changed, 10 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 30007afe70b3..d898b32dedcc 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -870,8 +870,7 @@ unsigned int skb_seq_read(unsigned int consumed, const u8 **data, void skb_abort_seq_read(struct skb_seq_state *st); unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, - unsigned int to, struct ts_config *config, - struct ts_state *state); + unsigned int to, struct ts_config *config); /* * Packet hash types specify the type of hash in skb_set_hash. diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 88c613eab142..374e43bc6b80 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2865,7 +2865,6 @@ static void skb_ts_finish(struct ts_config *conf, struct ts_state *state) * @from: search offset * @to: search limit * @config: textsearch configuration - * @state: uninitialized textsearch state variable * * Finds a pattern in the skb data according to the specified * textsearch configuration. Use textsearch_next() to retrieve @@ -2873,17 +2872,17 @@ static void skb_ts_finish(struct ts_config *conf, struct ts_state *state) * to the first occurrence or UINT_MAX if no match was found. */ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, - unsigned int to, struct ts_config *config, - struct ts_state *state) + unsigned int to, struct ts_config *config) { + struct ts_state state; unsigned int ret; config->get_next_block = skb_ts_get_next_block; config->finish = skb_ts_finish; - skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state)); + skb_prepare_seq_read(skb, from, to, TS_SKB_CB(&state)); - ret = textsearch_find(config, state); + ret = textsearch_find(config, &state); return (ret <= to - from ? ret : UINT_MAX); } EXPORT_SYMBOL(skb_find_text); diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c index b8b95f4027ca..57a26cc90c9f 100644 --- a/net/netfilter/nf_conntrack_amanda.c +++ b/net/netfilter/nf_conntrack_amanda.c @@ -88,7 +88,6 @@ static int amanda_help(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { - struct ts_state ts; struct nf_conntrack_expect *exp; struct nf_conntrack_tuple *tuple; unsigned int dataoff, start, stop, off, i; @@ -113,23 +112,20 @@ static int amanda_help(struct sk_buff *skb, return NF_ACCEPT; } - memset(&ts, 0, sizeof(ts)); start = skb_find_text(skb, dataoff, skb->len, - search[SEARCH_CONNECT].ts, &ts); + search[SEARCH_CONNECT].ts); if (start == UINT_MAX) goto out; start += dataoff + search[SEARCH_CONNECT].len; - memset(&ts, 0, sizeof(ts)); stop = skb_find_text(skb, start, skb->len, - search[SEARCH_NEWLINE].ts, &ts); + search[SEARCH_NEWLINE].ts); if (stop == UINT_MAX) goto out; stop += start; for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) { - memset(&ts, 0, sizeof(ts)); - off = skb_find_text(skb, start, stop, search[i].ts, &ts); + off = skb_find_text(skb, start, stop, search[i].ts); if (off == UINT_MAX) continue; off += start + search[i].len; diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c index 5699adb97652..0bc3460319c8 100644 --- a/net/netfilter/xt_string.c +++ b/net/netfilter/xt_string.c @@ -26,13 +26,12 @@ static bool string_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_string_info *conf = par->matchinfo; - struct ts_state state; bool invert; invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT; return (skb_find_text((struct sk_buff *)skb, conf->from_offset, - conf->to_offset, conf->config, &state) + conf->to_offset, conf->config) != UINT_MAX) ^ invert; } diff --git a/net/sched/em_text.c b/net/sched/em_text.c index f03c3de16c27..73e2ed576ceb 100644 --- a/net/sched/em_text.c +++ b/net/sched/em_text.c @@ -34,7 +34,6 @@ static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m, { struct text_match *tm = EM_TEXT_PRIV(m); int from, to; - struct ts_state state; from = tcf_get_base_ptr(skb, tm->from_layer) - skb->data; from += tm->from_offset; @@ -42,7 +41,7 @@ static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m, to = tcf_get_base_ptr(skb, tm->to_layer) - skb->data; to += tm->to_offset; - return skb_find_text(skb, from, to, tm->config, &state) != UINT_MAX; + return skb_find_text(skb, from, to, tm->config) != UINT_MAX; } static int em_text_change(struct net *net, void *data, int len, -- cgit v1.2.3 From 0dc6f20b9803f09726bbb682649d35cda8ef5b5d Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 21 Jan 2015 11:46:32 -0800 Subject: drm/i915/bdw: PCI IDs ending in 0xb are ULT. When reviewing patch that fixes VGA on BDW Halo Jani noticed that we also had other ULT IDs that weren't listed there. So this follow-up patch add these pci-ids as halo and fix comments on i915_pciids.h Cc: Jani Nikula Cc: stable@vger.kernel.org Signed-off-by: Rodrigo Vivi Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 1 + include/drm/i915_pciids.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f2a825e39646..b38c770a22f5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2374,6 +2374,7 @@ struct drm_i915_cmd_table { (INTEL_DEVID(dev) & 0xFF00) == 0x0C00) #define IS_BDW_ULT(dev) (IS_BROADWELL(dev) && \ ((INTEL_DEVID(dev) & 0xf) == 0x6 || \ + (INTEL_DEVID(dev) & 0xf) == 0xb || \ (INTEL_DEVID(dev) & 0xf) == 0xe)) #define IS_BDW_GT3(dev) (IS_BROADWELL(dev) && \ (INTEL_DEVID(dev) & 0x00F0) == 0x0020) diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 180ad0e6de21..d016dc57f007 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -214,9 +214,9 @@ INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info) #define _INTEL_BDW_M_IDS(gt, info) \ - _INTEL_BDW_M(gt, 0x1602, info), /* ULT */ \ + _INTEL_BDW_M(gt, 0x1602, info), /* Halo */ \ _INTEL_BDW_M(gt, 0x1606, info), /* ULT */ \ - _INTEL_BDW_M(gt, 0x160B, info), /* Iris */ \ + _INTEL_BDW_M(gt, 0x160B, info), /* ULT */ \ _INTEL_BDW_M(gt, 0x160E, info) /* ULX */ #define _INTEL_BDW_D_IDS(gt, info) \ -- cgit v1.2.3 From 9625604cebcb3f5be2e692408274734e8ae63979 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 13 Feb 2015 21:03:42 +0100 Subject: drm/irq: Add drm_crtc_vblank_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At driver load we need to tell the vblank code about the state of the pipes, so that the logic around reject vblank_get when the pipe is off works correctly. Thus far i915 used drm_vblank_off, but one of the side-effects of it is that it also saves the vblank counter. And for that it calls down into the ->get_vblank_counter hook. Which isn't really a good idea when the pipe is off for a few reasons: - With runtime pm the register might not respond. - If the pipe is off some datastructures might not be around or unitialized. The later is what blew up on gen3: We look at intel_crtc->config to compute the vblank counter, and for a disabled pipe at boot-up that's just not there. Thus far this was papered over by a check for intel_crtc->active, but I want to get rid of that (since it's fairly race, vblank hooks are called from all kinds of places). So prep for that by adding a _reset functions which only does what we really need to be done at driver load: Mark the vblank pipe as off, but don't do any vblank counter saving or event flushing - neither of that is required. v2: Clarify the code flow slightly as suggested by Ville. v3: Fix kerneldoc spelling, spotted by Laurent. Cc: Ville Syrjälä Cc: Laurent Pinchart Cc: Imre Deak Reviewed-by: Imre Deak (v2) Acked-by: Dave Airlie Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 32 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 6 +++--- include/drm/drmP.h | 1 + 3 files changed, 36 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 75647e7f012b..e78a1f5cad9c 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1225,6 +1225,38 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_vblank_off); +/** + * drm_crtc_vblank_reset - reset vblank state to off on a CRTC + * @crtc: CRTC in question + * + * Drivers can use this function to reset the vblank state to off at load time. + * Drivers should use this together with the drm_crtc_vblank_off() and + * drm_crtc_vblank_on() functions. The difference compared to + * drm_crtc_vblank_off() is that this function doesn't save the vblank counter + * and hence doesn't need to call any driver hooks. + */ +void drm_crtc_vblank_reset(struct drm_crtc *drm_crtc) +{ + struct drm_device *dev = drm_crtc->dev; + unsigned long irqflags; + int crtc = drm_crtc_index(drm_crtc); + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; + + spin_lock_irqsave(&dev->vbl_lock, irqflags); + /* + * Prevent subsequent drm_vblank_get() from enabling the vblank + * interrupt by bumping the refcount. + */ + if (!vblank->inmodeset) { + atomic_inc(&vblank->refcount); + vblank->inmodeset = 1; + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + WARN_ON(!list_empty(&dev->vblank_event_list)); +} +EXPORT_SYMBOL(drm_crtc_vblank_reset); + /** * drm_vblank_on - enable vblank events on a CRTC * @dev: DRM device diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3b0fe9f1f3c9..b901b00a8f2e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13316,11 +13316,11 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); /* restore vblank interrupts to correct state */ + drm_crtc_vblank_reset(&crtc->base); if (crtc->active) { update_scanline_offset(crtc); - drm_vblank_on(dev, crtc->pipe); - } else - drm_vblank_off(dev, crtc->pipe); + drm_crtc_vblank_on(&crtc->base); + } /* We need to sanitize the plane -> pipe mapping first because this will * disable the crtc (and hence change the state) if it is wrong. Note diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e928625a9da0..54c6ea1e5866 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -922,6 +922,7 @@ extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc); extern void drm_vblank_on(struct drm_device *dev, int crtc); extern void drm_crtc_vblank_off(struct drm_crtc *crtc); +extern void drm_crtc_vblank_reset(struct drm_crtc *crtc); extern void drm_crtc_vblank_on(struct drm_crtc *crtc); extern void drm_vblank_cleanup(struct drm_device *dev); -- cgit v1.2.3 From 498b8738485ab1a327163f771953f32cf35ca3b5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 16 Feb 2015 15:12:31 +0000 Subject: drm: Fix the CRTC_STEREO_DOUBLE_ONLY define to include stero modes The CRTC_STEREO_DOUBLE_ONLY define was introduced in commit: commit ecb7e16bf187bc369cf6a5cd108582c01329980d Author: Gustavo Padovan Date: Mon Dec 1 15:40:09 2014 -0800 drm: add helper to get crtc timings (v5) but if we want the stereo h/v adjustments, we need to set the CRTC_STEREO_DOUBLE flag. Otherwise, we'll get the wrong h/v for frame packing stereo 3d modes. Cc: Gustavo Padovan Cc: Matt Roper Cc: Ander Conselvan de Oliveira Signed-off-by: Damien Lespiau Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- include/drm/drm_modes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index d92f6dd1fb11..0616188c7801 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -92,7 +92,7 @@ enum drm_mode_status { #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ #define CRTC_NO_DBLSCAN (1 << 2) /* don't adjust doublescan */ #define CRTC_NO_VSCAN (1 << 3) /* don't adjust doublescan */ -#define CRTC_STEREO_DOUBLE_ONLY (CRTC_NO_DBLSCAN | CRTC_NO_VSCAN) +#define CRTC_STEREO_DOUBLE_ONLY (CRTC_STEREO_DOUBLE | CRTC_NO_DBLSCAN | CRTC_NO_VSCAN) #define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF -- cgit v1.2.3 From 17a38d9c254bf4e3b0d8b7ccd5c1988cb63730ff Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 22 Feb 2015 12:24:16 +0100 Subject: drm: Add DRM_DEBUG_ATOMIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atomic state handling adds a lot of indirection and complexity between simple updates and drivers. For easier debugging the diagnostic output is therefore rather chatty. Which is great for tracking down atomic issues, but really annoying otherwise. Add a new DRM_DEBUG_ATOMIC to be able to filter this out. Cc: Ville Syrjälä Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 100 +++++++++++++++-------------- drivers/gpu/drm/drm_atomic_helper.c | 124 ++++++++++++++++++------------------ include/drm/drmP.h | 9 +++ 3 files changed, 122 insertions(+), 111 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c2e9c5283136..321e098ddf04 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -92,7 +92,7 @@ drm_atomic_state_alloc(struct drm_device *dev) state->dev = dev; - DRM_DEBUG_KMS("Allocate atomic state %p\n", state); + DRM_DEBUG_ATOMIC("Allocate atomic state %p\n", state); return state; fail: @@ -122,7 +122,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) struct drm_mode_config *config = &dev->mode_config; int i; - DRM_DEBUG_KMS("Clearing atomic state %p\n", state); + DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state); for (i = 0; i < state->num_connector; i++) { struct drm_connector *connector = state->connectors[i]; @@ -172,7 +172,7 @@ void drm_atomic_state_free(struct drm_atomic_state *state) { drm_atomic_state_clear(state); - DRM_DEBUG_KMS("Freeing atomic state %p\n", state); + DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state); kfree_state(state); } @@ -217,8 +217,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, state->crtcs[index] = crtc; crtc_state->state = state; - DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n", - crtc->base.id, crtc_state, state); + DRM_DEBUG_ATOMIC("Added [CRTC:%d] %p state to %p\n", + crtc->base.id, crtc_state, state); return crtc_state; } @@ -293,8 +293,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, */ if (state->active && !state->enable) { - DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n", + crtc->base.id); return -EINVAL; } @@ -340,8 +340,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, state->planes[index] = plane; plane_state->state = state; - DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n", - plane->base.id, plane_state, state); + DRM_DEBUG_ATOMIC("Added [PLANE:%d] %p state to %p\n", + plane->base.id, plane_state, state); if (plane_state->crtc) { struct drm_crtc_state *crtc_state; @@ -477,10 +477,10 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* either *both* CRTC and FB must be set, or neither */ if (WARN_ON(state->crtc && !state->fb)) { - DRM_DEBUG_KMS("CRTC set but no FB\n"); + DRM_DEBUG_ATOMIC("CRTC set but no FB\n"); return -EINVAL; } else if (WARN_ON(state->fb && !state->crtc)) { - DRM_DEBUG_KMS("FB set but no CRTC\n"); + DRM_DEBUG_ATOMIC("FB set but no CRTC\n"); return -EINVAL; } @@ -490,7 +490,7 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* Check whether this plane is usable on this CRTC */ if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { - DRM_DEBUG_KMS("Invalid crtc for plane\n"); + DRM_DEBUG_ATOMIC("Invalid crtc for plane\n"); return -EINVAL; } @@ -499,8 +499,8 @@ static int drm_atomic_plane_check(struct drm_plane *plane, if (state->fb->pixel_format == plane->format_types[i]) break; if (i == plane->format_count) { - DRM_DEBUG_KMS("Invalid pixel format %s\n", - drm_get_format_name(state->fb->pixel_format)); + DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", + drm_get_format_name(state->fb->pixel_format)); return -EINVAL; } @@ -509,9 +509,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane, state->crtc_x > INT_MAX - (int32_t) state->crtc_w || state->crtc_h > INT_MAX || state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { - DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", - state->crtc_w, state->crtc_h, - state->crtc_x, state->crtc_y); + DRM_DEBUG_ATOMIC("Invalid CRTC coordinates %ux%u+%d+%d\n", + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); return -ERANGE; } @@ -523,12 +523,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane, state->src_x > fb_width - state->src_w || state->src_h > fb_height || state->src_y > fb_height - state->src_h) { - DRM_DEBUG_KMS("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", - state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, - state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, - state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, - state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); + DRM_DEBUG_ATOMIC("Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, + state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, + state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, + state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); return -ENOSPC; } @@ -575,7 +575,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, * at most the array is a bit too large. */ if (index >= state->num_connector) { - DRM_DEBUG_KMS("Hot-added connector would overflow state array, restarting\n"); + DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n"); return ERR_PTR(-EAGAIN); } @@ -590,8 +590,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, state->connectors[index] = connector; connector_state->state = state; - DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n", - connector->base.id, connector_state, state); + DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d] %p state to %p\n", + connector->base.id, connector_state, state); if (connector_state->crtc) { struct drm_crtc_state *crtc_state; @@ -752,10 +752,11 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, } if (crtc) - DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n", - plane_state, crtc->base.id); + DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d]\n", + plane_state, crtc->base.id); else - DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state); + DRM_DEBUG_ATOMIC("Link plane state %p to [NOCRTC]\n", + plane_state); return 0; } @@ -782,10 +783,11 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, plane_state->fb = fb; if (fb) - DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n", - fb->base.id, plane_state); + DRM_DEBUG_ATOMIC("Set [FB:%d] for plane state %p\n", + fb->base.id, plane_state); else - DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state); + DRM_DEBUG_ATOMIC("Set [NOFB] for plane state %p\n", + plane_state); } EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); @@ -818,11 +820,11 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, conn_state->crtc = crtc; if (crtc) - DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n", - conn_state, crtc->base.id); + DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d]\n", + conn_state, crtc->base.id); else - DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n", - conn_state); + DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n", + conn_state); return 0; } @@ -858,8 +860,8 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, if (ret) return ret; - DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n", - crtc->base.id, state); + DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d] to %p\n", + crtc->base.id, state); /* * Changed connectors are already in @state, so only need to look at the @@ -901,8 +903,8 @@ drm_atomic_connectors_for_crtc(struct drm_atomic_state *state, num_connected_connectors++; } - DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n", - state, num_connected_connectors, crtc->base.id); + DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d]\n", + state, num_connected_connectors, crtc->base.id); return num_connected_connectors; } @@ -953,7 +955,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state) int ncrtcs = config->num_crtc; int i, ret = 0; - DRM_DEBUG_KMS("checking %p\n", state); + DRM_DEBUG_ATOMIC("checking %p\n", state); for (i = 0; i < nplanes; i++) { struct drm_plane *plane = state->planes[i]; @@ -963,8 +965,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ret = drm_atomic_plane_check(plane, state->plane_states[i]); if (ret) { - DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n", - plane->base.id); + DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n", + plane->base.id); return ret; } } @@ -977,8 +979,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]); if (ret) { - DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n", + crtc->base.id); return ret; } } @@ -996,8 +998,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (crtc_state->mode_changed || crtc_state->active_changed) { - DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n", + crtc->base.id); return -EINVAL; } } @@ -1032,7 +1034,7 @@ int drm_atomic_commit(struct drm_atomic_state *state) if (ret) return ret; - DRM_DEBUG_KMS("commiting %p\n", state); + DRM_DEBUG_ATOMIC("commiting %p\n", state); return config->funcs->atomic_commit(state->dev, state, false); } @@ -1063,7 +1065,7 @@ int drm_atomic_async_commit(struct drm_atomic_state *state) if (ret) return ret; - DRM_DEBUG_KMS("commiting %p asynchronously\n", state); + DRM_DEBUG_ATOMIC("commiting %p asynchronously\n", state); return config->funcs->atomic_commit(state->dev, state, true); } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e70adfcb9e84..9e8767118edb 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -116,9 +116,9 @@ steal_encoder(struct drm_atomic_state *state, */ WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - DRM_DEBUG_KMS("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n", - encoder->base.id, encoder->name, - encoder_crtc->base.id); + DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n", + encoder->base.id, encoder->name, + encoder_crtc->base.id); crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc); if (IS_ERR(crtc_state)) @@ -130,9 +130,9 @@ steal_encoder(struct drm_atomic_state *state, if (connector->state->best_encoder != encoder) continue; - DRM_DEBUG_KMS("Stealing encoder from [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("Stealing encoder from [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); connector_state = drm_atomic_get_connector_state(state, connector); @@ -165,9 +165,9 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) if (!connector) return 0; - DRM_DEBUG_KMS("Updating routing for [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("Updating routing for [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); if (connector->state->crtc != connector_state->crtc) { if (connector->state->crtc) { @@ -186,7 +186,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) } if (!connector_state->crtc) { - DRM_DEBUG_KMS("Disabling [CONNECTOR:%d:%s]\n", + DRM_DEBUG_ATOMIC("Disabling [CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -199,19 +199,19 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) new_encoder = funcs->best_encoder(connector); if (!new_encoder) { - DRM_DEBUG_KMS("No suitable encoder found for [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); return -EINVAL; } if (new_encoder == connector_state->best_encoder) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n", - connector->base.id, - connector->name, - new_encoder->base.id, - new_encoder->name, - connector_state->crtc->base.id); + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n", + connector->base.id, + connector->name, + new_encoder->base.id, + new_encoder->name, + connector_state->crtc->base.id); return 0; } @@ -222,9 +222,9 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) if (encoder_crtc) { ret = steal_encoder(state, new_encoder, encoder_crtc); if (ret) { - DRM_DEBUG_KMS("Encoder stealing failed for [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("Encoder stealing failed for [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); return ret; } } @@ -235,12 +235,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) crtc_state = state->crtc_states[idx]; crtc_state->mode_changed = true; - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", - connector->base.id, - connector->name, - new_encoder->base.id, - new_encoder->name, - connector_state->crtc->base.id); + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", + connector->base.id, + connector->name, + new_encoder->base.id, + new_encoder->name, + connector_state->crtc->base.id); return 0; } @@ -292,7 +292,7 @@ mode_fixup(struct drm_atomic_state *state) encoder->bridge, &crtc_state->mode, &crtc_state->adjusted_mode); if (!ret) { - DRM_DEBUG_KMS("Bridge fixup failed\n"); + DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); return -EINVAL; } } @@ -301,16 +301,16 @@ mode_fixup(struct drm_atomic_state *state) ret = funcs->atomic_check(encoder, crtc_state, conn_state); if (ret) { - DRM_DEBUG_KMS("[ENCODER:%d:%s] check failed\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] check failed\n", + encoder->base.id, encoder->name); return ret; } } else { ret = funcs->mode_fixup(encoder, &crtc_state->mode, &crtc_state->adjusted_mode); if (!ret) { - DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] fixup failed\n", + encoder->base.id, encoder->name); return -EINVAL; } } @@ -330,8 +330,8 @@ mode_fixup(struct drm_atomic_state *state) ret = funcs->mode_fixup(crtc, &crtc_state->mode, &crtc_state->adjusted_mode); if (!ret) { - DRM_DEBUG_KMS("[CRTC:%d] fixup failed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] fixup failed\n", + crtc->base.id); return -EINVAL; } } @@ -384,14 +384,14 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, continue; if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) { - DRM_DEBUG_KMS("[CRTC:%d] mode changed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] mode changed\n", + crtc->base.id); crtc_state->mode_changed = true; } if (crtc->state->enable != crtc_state->enable) { - DRM_DEBUG_KMS("[CRTC:%d] enable changed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] enable changed\n", + crtc->base.id); crtc_state->mode_changed = true; } } @@ -428,17 +428,17 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, * a full modeset because update_connector_routing force that. */ if (crtc->state->active != crtc_state->active) { - DRM_DEBUG_KMS("[CRTC:%d] active changed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] active changed\n", + crtc->base.id); crtc_state->active_changed = true; } if (!needs_modeset(crtc_state)) continue; - DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n", - crtc->base.id, - crtc_state->enable ? 'y' : 'n', + DRM_DEBUG_ATOMIC("[CRTC:%d] needs all connectors, enable: %c, active: %c\n", + crtc->base.id, + crtc_state->enable ? 'y' : 'n', crtc_state->active ? 'y' : 'n'); ret = drm_atomic_add_affected_connectors(state, crtc); @@ -449,8 +449,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, crtc); if (crtc_state->enable != !!num_connectors) { - DRM_DEBUG_KMS("[CRTC:%d] enabled/connectors mismatch\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] enabled/connectors mismatch\n", + crtc->base.id); return -EINVAL; } @@ -497,8 +497,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev, ret = funcs->atomic_check(plane, plane_state); if (ret) { - DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n", - plane->base.id); + DRM_DEBUG_ATOMIC("[PLANE:%d] atomic driver check failed\n", + plane->base.id); return ret; } } @@ -517,8 +517,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev, ret = funcs->atomic_check(crtc, state->crtc_states[i]); if (ret) { - DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] atomic driver check failed\n", + crtc->base.id); return ret; } } @@ -600,8 +600,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = encoder->helper_private; - DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); /* * Each encoder has at most one connector (since we always steal @@ -639,8 +639,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = crtc->helper_private; - DRM_DEBUG_KMS("disabling [CRTC:%d]\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("disabling [CRTC:%d]\n", + crtc->base.id); /* Right function depends upon target state. */ @@ -724,8 +724,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = crtc->helper_private; if (crtc->state->enable) { - DRM_DEBUG_KMS("modeset on [CRTC:%d]\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("modeset on [CRTC:%d]\n", + crtc->base.id); funcs->mode_set_nofb(crtc); } @@ -752,8 +752,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) if (!new_crtc_state->mode_changed) continue; - DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("modeset on [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); /* * Each encoder has at most one connector (since we always steal @@ -816,8 +816,8 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, funcs = crtc->helper_private; if (crtc->state->enable) { - DRM_DEBUG_KMS("enabling [CRTC:%d]\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("enabling [CRTC:%d]\n", + crtc->base.id); if (funcs->enable) funcs->enable(crtc); @@ -842,8 +842,8 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, encoder = connector->state->best_encoder; funcs = encoder->helper_private; - DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); /* * Each encoder has at most one connector (since we always steal diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e928625a9da0..52999ba9fbaf 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -104,6 +104,9 @@ struct dma_buf_attachment; * PRIME: used in the prime code. * This is the category used by the DRM_DEBUG_PRIME() macro. * + * ATOMIC: used in the atomic code. + * This is the category used by the DRM_DEBUG_ATOMIC() macro. + * * Enabling verbose debug messages is done through the drm.debug parameter, * each category being enabled by a bit. * @@ -121,6 +124,7 @@ struct dma_buf_attachment; #define DRM_UT_DRIVER 0x02 #define DRM_UT_KMS 0x04 #define DRM_UT_PRIME 0x08 +#define DRM_UT_ATOMIC 0x10 extern __printf(2, 3) void drm_ut_debug_printk(const char *function_name, @@ -207,6 +211,11 @@ void drm_err(const char *format, ...); if (unlikely(drm_debug & DRM_UT_PRIME)) \ drm_ut_debug_printk(__func__, fmt, ##args); \ } while (0) +#define DRM_DEBUG_ATOMIC(fmt, args...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_ATOMIC)) \ + drm_ut_debug_printk(__func__, fmt, ##args); \ + } while (0) /*@}*/ -- cgit v1.2.3 From ee8905963ed0bc9dfc0952dc35e16e233c10e212 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 14 Apr 2014 17:53:25 +0200 Subject: of: Add for_each_endpoint_of_node helper macro Note that while of_graph_get_next_endpoint decrements the reference count of the child node passed to it, of_node_put(child) still has to be called manually when breaking out of the loop. Signed-off-by: Philipp Zabel Acked-by: Laurent Pinchart --- include/linux/of_graph.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index befef42e015b..e43442efcbe5 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -26,6 +26,17 @@ struct of_endpoint { const struct device_node *local_node; }; +/** + * for_each_endpoint_of_node - iterate over every endpoint in a device node + * @parent: parent device node containing ports and endpoints + * @child: loop variable pointing to the current endpoint node + * + * When breaking out of the loop, of_node_put(child) has to be called manually. + */ +#define for_each_endpoint_of_node(parent, child) \ + for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \ + child = of_graph_get_next_endpoint(parent, child)) + #ifdef CONFIG_OF int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint); -- cgit v1.2.3 From 411fdaf846afb0be1b54383c184f58a42fa416ff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 17 Feb 2015 01:46:49 +0000 Subject: dmaengine: shdma: use normal interface for passing slave id in dma_slave_config, which is incompatible with the way that the dmaengine API normally works. I've had a closer look at the existing code now and found that all slave drivers that pass a slave_id in dma_slave_config for SH do that right after passing the same ID into shdma_chan_filter, so we can just rely on that. However, the various shdma drivers currently do not remember the slave ID that was passed into the filter function when used in non-DT mode and only check the value to find a matching channel, unlike all other drivers. There might still be drivers that are not part of the kernel that rely on setting the slave_id to some other value, so to be on the safe side, this adds another 'real_slave_id' field to shdma_chan that remembers the ID and uses it when a driver passes a zero slave_id in dma_slave_config, like most drivers do. Eventually, the real_slave_id and slave_id fields should just get merged into one field, but that requires other changes. Signed-off-by: Arnd Bergmann Signed-off-by: Kuninori Morimoto Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma-base.c | 73 ++++++++++++++++++++++++++++++++------------- include/linux/shdma-base.h | 1 + 2 files changed, 54 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 8ee383d339a5..10fcabad80f3 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -171,8 +171,7 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan) return NULL; } -static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, - dma_addr_t slave_addr) +static int shdma_setup_slave(struct shdma_chan *schan, dma_addr_t slave_addr) { struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); const struct shdma_ops *ops = sdev->ops; @@ -183,25 +182,23 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, ret = ops->set_slave(schan, match, slave_addr, true); if (ret < 0) return ret; - - slave_id = schan->slave_id; } else { - match = slave_id; + match = schan->real_slave_id; } - if (slave_id < 0 || slave_id >= slave_num) + if (schan->real_slave_id < 0 || schan->real_slave_id >= slave_num) return -EINVAL; - if (test_and_set_bit(slave_id, shdma_slave_used)) + if (test_and_set_bit(schan->real_slave_id, shdma_slave_used)) return -EBUSY; ret = ops->set_slave(schan, match, slave_addr, false); if (ret < 0) { - clear_bit(slave_id, shdma_slave_used); + clear_bit(schan->real_slave_id, shdma_slave_used); return ret; } - schan->slave_id = slave_id; + schan->slave_id = schan->real_slave_id; return 0; } @@ -221,10 +218,12 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan) */ if (slave) { /* Legacy mode: .private is set in filter */ - ret = shdma_setup_slave(schan, slave->slave_id, 0); + schan->real_slave_id = slave->slave_id; + ret = shdma_setup_slave(schan, 0); if (ret < 0) goto esetslave; } else { + /* Normal mode: real_slave_id was set by filter */ schan->slave_id = -EINVAL; } @@ -258,11 +257,14 @@ esetslave: /* * This is the standard shdma filter function to be used as a replacement to the - * "old" method, using the .private pointer. If for some reason you allocate a - * channel without slave data, use something like ERR_PTR(-EINVAL) as a filter + * "old" method, using the .private pointer. + * You always have to pass a valid slave id as the argument, old drivers that + * pass ERR_PTR(-EINVAL) as a filter parameter and set it up in dma_slave_config + * need to be updated so we can remove the slave_id field from dma_slave_config. * parameter. If this filter is used, the slave driver, after calling * dma_request_channel(), will also have to call dmaengine_slave_config() with - * .slave_id, .direction, and either .src_addr or .dst_addr set. + * .direction, and either .src_addr or .dst_addr set. + * * NOTE: this filter doesn't support multiple DMAC drivers with the DMA_SLAVE * capability! If this becomes a requirement, hardware glue drivers, using this * services would have to provide their own filters, which first would check @@ -276,7 +278,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) { struct shdma_chan *schan; struct shdma_dev *sdev; - int match = (long)arg; + int slave_id = (long)arg; int ret; /* Only support channels handled by this driver. */ @@ -284,19 +286,39 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) shdma_alloc_chan_resources) return false; - if (match < 0) + schan = to_shdma_chan(chan); + sdev = to_shdma_dev(chan->device); + + /* + * For DT, the schan->slave_id field is generated by the + * set_slave function from the slave ID that is passed in + * from xlate. For the non-DT case, the slave ID is + * directly passed into the filter function by the driver + */ + if (schan->dev->of_node) { + ret = sdev->ops->set_slave(schan, slave_id, 0, true); + if (ret < 0) + return false; + + schan->real_slave_id = schan->slave_id; + return true; + } + + if (slave_id < 0) { /* No slave requested - arbitrary channel */ + dev_warn(sdev->dma_dev.dev, "invalid slave ID passed to dma_request_slave\n"); return true; + } - schan = to_shdma_chan(chan); - if (!schan->dev->of_node && match >= slave_num) + if (slave_id >= slave_num) return false; - sdev = to_shdma_dev(schan->dma_chan.device); - ret = sdev->ops->set_slave(schan, match, 0, true); + ret = sdev->ops->set_slave(schan, slave_id, 0, true); if (ret < 0) return false; + schan->real_slave_id = slave_id; + return true; } EXPORT_SYMBOL(shdma_chan_filter); @@ -452,6 +474,8 @@ static void shdma_free_chan_resources(struct dma_chan *chan) chan->private = NULL; } + schan->real_slave_id = 0; + spin_lock_irq(&schan->chan_lock); list_splice_init(&schan->ld_free, &list); @@ -764,11 +788,20 @@ static int shdma_config(struct dma_chan *chan, */ if (!config) return -EINVAL; + + /* + * overriding the slave_id through dma_slave_config is deprecated, + * but possibly some out-of-tree drivers still do it. + */ + if (WARN_ON_ONCE(config->slave_id && + config->slave_id != schan->real_slave_id)) + schan->real_slave_id = config->slave_id; + /* * We could lock this, but you shouldn't be configuring the * channel, while using it... */ - return shdma_setup_slave(schan, config->slave_id, + return shdma_setup_slave(schan, config->direction == DMA_DEV_TO_MEM ? config->src_addr : config->dst_addr); } diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index abdf1f229dc3..dd0ba502ccb3 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -69,6 +69,7 @@ struct shdma_chan { int id; /* Raw id of this channel */ int irq; /* Channel IRQ */ int slave_id; /* Client ID for slave DMA */ + int real_slave_id; /* argument passed to filter function */ int hw_req; /* DMA request line for slave DMA - same * as MID/RID, used with DT */ enum shdma_pm_state pm_state; -- cgit v1.2.3 From bfe446e37c4efd8ade454911e8f80414bcbfc10d Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 11 Mar 2014 11:21:11 +0100 Subject: of: Add of_graph_get_port_by_id function This patch adds a function to get a port device tree node by port id, or reg property value. Signed-off-by: Philipp Zabel Acked-by: Laurent Pinchart --- drivers/of/base.c | 32 ++++++++++++++++++++++++++++++++ include/linux/of_graph.h | 7 +++++++ 2 files changed, 39 insertions(+) (limited to 'include') diff --git a/drivers/of/base.c b/drivers/of/base.c index 05b20f1cca7b..6398b9ca9157 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2080,6 +2080,38 @@ int of_graph_parse_endpoint(const struct device_node *node, } EXPORT_SYMBOL(of_graph_parse_endpoint); +/** + * of_graph_get_port_by_id() - get the port matching a given id + * @parent: pointer to the parent device node + * @id: id of the port + * + * Return: A 'port' node pointer with refcount incremented. The caller + * has to use of_node_put() on it when done. + */ +struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) +{ + struct device_node *node, *port; + + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + for_each_child_of_node(parent, port) { + u32 port_id = 0; + + if (of_node_cmp(port->name, "port") != 0) + continue; + of_property_read_u32(port, "reg", &port_id); + if (id == port_id) + break; + } + + of_node_put(node); + + return port; +} +EXPORT_SYMBOL(of_graph_get_port_by_id); + /** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index e43442efcbe5..3c1c95a39e0c 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -40,6 +40,7 @@ struct of_endpoint { #ifdef CONFIG_OF int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint); +struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous); struct device_node *of_graph_get_remote_port_parent( @@ -53,6 +54,12 @@ static inline int of_graph_parse_endpoint(const struct device_node *node, return -ENOSYS; } +static inline struct device_node *of_graph_get_port_by_id( + struct device_node *node, u32 id) +{ + return NULL; +} + static inline struct device_node *of_graph_get_next_endpoint( const struct device_node *parent, struct device_node *previous) -- cgit v1.2.3 From ca8895d9bb41e743271c42a4438a296de891b73b Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Wed, 26 Nov 2014 12:22:03 -0600 Subject: Return MD_SB_CLUSTERED if mddev is clustered Signed-off-by: Goldwyn Rodrigues --- drivers/md/md.c | 3 +++ include/uapi/linux/raid/md_p.h | 1 + 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/drivers/md/md.c b/drivers/md/md.c index 3387f940140b..5ed57688e5c5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5634,6 +5634,9 @@ static int get_array_info(struct mddev *mddev, void __user *arg) info.state = (1<bitmap && mddev->bitmap_info.offset) info.state |= (1< Date: Thu, 19 Feb 2015 15:31:25 -0800 Subject: HID: hid-sensor-hub: Allow parallel synchronous reads Current implementation only allows one outstanding synchronous read. This is a performance hit when user mode is requesting raw reads of sensor attributes on multiple sensors together. This change changes the mutex lock to per hid sensor hub device instead of global lock. Although request to hid sensor hub is serialized, there can be multiple outstanding read requests pending for responses via hid reports. Signed-off-by: Srinivas Pandruvada Acked-by: Jonathan Cameron Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 90 +++++++++++++++++++----------------------- include/linux/hid-sensor-hub.h | 24 +++++++++++ 2 files changed, 65 insertions(+), 49 deletions(-) (limited to 'include') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 6a58b6c723aa..62fadf8c86fc 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -28,30 +28,11 @@ #define HID_SENSOR_HUB_ENUM_QUIRK 0x01 -/** - * struct sensor_hub_pending - Synchronous read pending information - * @status: Pending status true/false. - * @ready: Completion synchronization data. - * @usage_id: Usage id for physical device, E.g. Gyro usage id. - * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. - * @raw_size: Response size for a read request. - * @raw_data: Place holder for received response. - */ -struct sensor_hub_pending { - bool status; - struct completion ready; - u32 usage_id; - u32 attr_usage_id; - int raw_size; - u8 *raw_data; -}; - /** * struct sensor_hub_data - Hold a instance data for a HID hub device * @hsdev: Stored hid instance for current hub device. * @mutex: Mutex to serialize synchronous request. * @lock: Spin lock to protect pending request structure. - * @pending: Holds information of pending sync read request. * @dyn_callback_list: Holds callback function * @dyn_callback_lock: spin lock to protect callback list * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. @@ -61,7 +42,6 @@ struct sensor_hub_pending { struct sensor_hub_data { struct mutex mutex; spinlock_t lock; - struct sensor_hub_pending pending; struct list_head dyn_callback_list; spinlock_t dyn_callback_lock; struct mfd_cell *hid_sensor_hub_client_devs; @@ -264,40 +244,42 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, struct hid_report *report; int ret_val = 0; - mutex_lock(&data->mutex); - memset(&data->pending, 0, sizeof(data->pending)); - init_completion(&data->pending.ready); - data->pending.usage_id = usage_id; - data->pending.attr_usage_id = attr_usage_id; - data->pending.raw_size = 0; + mutex_lock(&hsdev->mutex); + memset(&hsdev->pending, 0, sizeof(hsdev->pending)); + init_completion(&hsdev->pending.ready); + hsdev->pending.usage_id = usage_id; + hsdev->pending.attr_usage_id = attr_usage_id; + hsdev->pending.raw_size = 0; spin_lock_irqsave(&data->lock, flags); - data->pending.status = true; + hsdev->pending.status = true; spin_unlock_irqrestore(&data->lock, flags); report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT); if (!report) goto err_free; + mutex_lock(&data->mutex); hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); - wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5); - switch (data->pending.raw_size) { + mutex_unlock(&data->mutex); + wait_for_completion_interruptible_timeout(&hsdev->pending.ready, HZ*5); + switch (hsdev->pending.raw_size) { case 1: - ret_val = *(u8 *)data->pending.raw_data; + ret_val = *(u8 *)hsdev->pending.raw_data; break; case 2: - ret_val = *(u16 *)data->pending.raw_data; + ret_val = *(u16 *)hsdev->pending.raw_data; break; case 4: - ret_val = *(u32 *)data->pending.raw_data; + ret_val = *(u32 *)hsdev->pending.raw_data; break; default: ret_val = 0; } - kfree(data->pending.raw_data); + kfree(hsdev->pending.raw_data); err_free: - data->pending.status = false; - mutex_unlock(&data->mutex); + hsdev->pending.status = false; + mutex_unlock(&hsdev->mutex); return ret_val; } @@ -453,16 +435,6 @@ static int sensor_hub_raw_event(struct hid_device *hdev, report->field[i]->report_count)/8); sz = (report->field[i]->report_size * report->field[i]->report_count)/8; - if (pdata->pending.status && pdata->pending.attr_usage_id == - report->field[i]->usage->hid) { - hid_dbg(hdev, "data was pending ...\n"); - pdata->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); - if (pdata->pending.raw_data) - pdata->pending.raw_size = sz; - else - pdata->pending.raw_size = 0; - complete(&pdata->pending.ready); - } collection = &hdev->collection[ report->field[i]->usage->collection_index]; hid_dbg(hdev, "collection->usage %x\n", @@ -472,8 +444,21 @@ static int sensor_hub_raw_event(struct hid_device *hdev, report->field[i]->physical, report->field[i]->usage[0].collection_index, &hsdev, &priv); - - if (callback && callback->capture_sample) { + if (!callback) { + ptr += sz; + continue; + } + if (hsdev->pending.status && hsdev->pending.attr_usage_id == + report->field[i]->usage->hid) { + hid_dbg(hdev, "data was pending ...\n"); + hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); + if (hsdev->pending.raw_data) + hsdev->pending.raw_size = sz; + else + hsdev->pending.raw_size = 0; + complete(&hsdev->pending.ready); + } + if (callback->capture_sample) { if (report->field[i]->logical) callback->capture_sample(hsdev, report->field[i]->logical, sz, ptr, @@ -628,6 +613,8 @@ static int sensor_hub_probe(struct hid_device *hdev, hsdev->hdev = hdev; hsdev->vendor_id = hdev->vendor; hsdev->product_id = hdev->product; + hsdev->usage = collection->usage; + mutex_init(&hsdev->mutex); hsdev->start_collection_index = i; if (last_hsdev) last_hsdev->end_collection_index = i; @@ -674,13 +661,18 @@ static void sensor_hub_remove(struct hid_device *hdev) { struct sensor_hub_data *data = hid_get_drvdata(hdev); unsigned long flags; + int i; hid_dbg(hdev, " hardware removed\n"); hid_hw_close(hdev); hid_hw_stop(hdev); spin_lock_irqsave(&data->lock, flags); - if (data->pending.status) - complete(&data->pending.ready); + for (i = 0; i < data->hid_sensor_client_cnt; ++i) { + struct hid_sensor_hub_device *hsdev = + data->hid_sensor_hub_client_devs[i].platform_data; + if (hsdev->pending.status) + complete(&hsdev->pending.ready); + } spin_unlock_irqrestore(&data->lock, flags); mfd_remove_devices(&hdev->dev); hid_set_drvdata(hdev, NULL); diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 51f7ccadf923..60a34277ddf2 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -46,20 +46,44 @@ struct hid_sensor_hub_attribute_info { s32 logical_maximum; }; +/** + * struct sensor_hub_pending - Synchronous read pending information + * @status: Pending status true/false. + * @ready: Completion synchronization data. + * @usage_id: Usage id for physical device, E.g. Gyro usage id. + * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. + * @raw_size: Response size for a read request. + * @raw_data: Place holder for received response. + */ +struct sensor_hub_pending { + bool status; + struct completion ready; + u32 usage_id; + u32 attr_usage_id; + int raw_size; + u8 *raw_data; +}; + /** * struct hid_sensor_hub_device - Stores the hub instance data * @hdev: Stores the hid instance. * @vendor_id: Vendor id of hub device. * @product_id: Product id of hub device. + * @usage: Usage id for this hub device instance. * @start_collection_index: Starting index for a phy type collection * @end_collection_index: Last index for a phy type collection + * @mutex: synchronizing mutex. + * @pending: Holds information of pending sync read request. */ struct hid_sensor_hub_device { struct hid_device *hdev; u32 vendor_id; u32 product_id; + u32 usage; int start_collection_index; int end_collection_index; + struct mutex mutex; + struct sensor_hub_pending pending; }; /** -- cgit v1.2.3 From cb67126f32f008b9abe97fbfca9b23a797b2458a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 19 Feb 2015 15:31:26 -0800 Subject: HID: hid-sensor-hub: Add support for application collection Section 4.2.5 of HID Sensor hub specification allows two methods defining sensor devices. - Each sensor device by its own collection - A top level application collection object, including multiple sensors. In the first method, each sensor can be in its own sensor application collection without a physical collection. In the second method there is a usage id for collection type, which is defined as an application collection, with multiple physical collections in it. It is possible to define fusion sensor with this and may have its own handler. If there is a callback registered for the collection type, then forward all reports for sensors in its collection to this handler. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 30 ++++++++++++++++++++++++++---- include/linux/hid-sensor-ids.h | 2 ++ 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 62fadf8c86fc..c325f85fa3a6 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -86,7 +86,8 @@ static int sensor_hub_get_physical_device_count(struct hid_device *hdev) for (i = 0; i < hdev->maxcollection; ++i) { struct hid_collection *collection = &hdev->collection[i]; - if (collection->type == HID_COLLECTION_PHYSICAL) + if (collection->type == HID_COLLECTION_PHYSICAL || + collection->type == HID_COLLECTION_APPLICATION) ++count; } @@ -118,7 +119,8 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback( spin_lock(&pdata->dyn_callback_lock); list_for_each_entry(callback, &pdata->dyn_callback_list, list) - if (callback->usage_id == usage_id && + if ((callback->usage_id == usage_id || + callback->usage_id == HID_USAGE_SENSOR_COLLECTION) && (collection_index >= callback->hsdev->start_collection_index) && (collection_index < @@ -157,7 +159,18 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, callback->usage_callback = usage_callback; callback->usage_id = usage_id; callback->priv = NULL; - list_add_tail(&callback->list, &pdata->dyn_callback_list); + /* + * If there is a handler registered for the collection type, then + * it will handle all reports for sensors in this collection. If + * there is also an individual sensor handler registration, then + * we want to make sure that the reports are directed to collection + * handler, as this may be a fusion sensor. So add collection handlers + * to the beginning of the list, so that they are matched first. + */ + if (usage_id == HID_USAGE_SENSOR_COLLECTION) + list_add(&callback->list, &pdata->dyn_callback_list); + else + list_add_tail(&callback->list, &pdata->dyn_callback_list); spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; @@ -555,6 +568,7 @@ static int sensor_hub_probe(struct hid_device *hdev, int dev_cnt; struct hid_sensor_hub_device *hsdev; struct hid_sensor_hub_device *last_hsdev = NULL; + struct hid_sensor_hub_device *collection_hsdev = NULL; sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); if (!sd) { @@ -601,7 +615,8 @@ static int sensor_hub_probe(struct hid_device *hdev, for (i = 0; i < hdev->maxcollection; ++i) { struct hid_collection *collection = &hdev->collection[i]; - if (collection->type == HID_COLLECTION_PHYSICAL) { + if (collection->type == HID_COLLECTION_PHYSICAL || + collection->type == HID_COLLECTION_APPLICATION) { hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev), GFP_KERNEL); @@ -638,10 +653,17 @@ static int sensor_hub_probe(struct hid_device *hdev, hid_dbg(hdev, "Adding %s:%d\n", name, hsdev->start_collection_index); sd->hid_sensor_client_cnt++; + if (collection_hsdev) + collection_hsdev->end_collection_index = i; + if (collection->type == HID_COLLECTION_APPLICATION && + collection->usage == HID_USAGE_SENSOR_COLLECTION) + collection_hsdev = hsdev; } } if (last_hsdev) last_hsdev->end_collection_index = i; + if (collection_hsdev) + collection_hsdev->end_collection_index = i; ret = mfd_add_hotplug_devices(&hdev->dev, sd->hid_sensor_hub_client_devs, diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 109f0e633e01..f2ee90aed0c2 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -21,6 +21,8 @@ #define HID_MAX_PHY_DEVICES 0xFF +#define HID_USAGE_SENSOR_COLLECTION 0x200001 + /* Accel 3D (200073) */ #define HID_USAGE_SENSOR_ACCEL_3D 0x200073 #define HID_USAGE_SENSOR_DATA_ACCELERATION 0x200452 -- cgit v1.2.3 From 8f4490e09694efaf7fe60ac6a1135530aa8c05ad Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:39:12 -0800 Subject: regulator: core: Introduce set_load op Expose the requested load directly to the regulator implementation for hardware that does not support the normal enum based set_mode(). Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/core.c | 39 ++++++++++++++++++++++++--------------- include/linux/regulator/driver.h | 3 +++ 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b899947d839d..f2452148c8da 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -648,10 +648,12 @@ static int drms_uA_update(struct regulator_dev *rdev) if (err < 0) return 0; - if (!rdev->desc->ops->get_optimum_mode) + if (!rdev->desc->ops->get_optimum_mode && + !rdev->desc->ops->set_load) return 0; - if (!rdev->desc->ops->set_mode) + if (!rdev->desc->ops->set_mode && + !rdev->desc->ops->set_load) return -EINVAL; /* get output voltage */ @@ -676,22 +678,29 @@ static int drms_uA_update(struct regulator_dev *rdev) list_for_each_entry(sibling, &rdev->consumer_list, list) current_uA += sibling->uA_load; - /* now get the optimum mode for our new total regulator load */ - mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, - output_uV, current_uA); + if (rdev->desc->ops->set_load) { + /* set the optimum mode for our new total regulator load */ + err = rdev->desc->ops->set_load(rdev, current_uA); + if (err < 0) + rdev_err(rdev, "failed to set load %d\n", current_uA); + } else { + /* now get the optimum mode for our new total regulator load */ + mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, + output_uV, current_uA); + + /* check the new mode is allowed */ + err = regulator_mode_constrain(rdev, &mode); + if (err < 0) { + rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", + current_uA, input_uV, output_uV); + return err; + } - /* check the new mode is allowed */ - err = regulator_mode_constrain(rdev, &mode); - if (err < 0) { - rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", - current_uA, input_uV, output_uV); - return err; + err = rdev->desc->ops->set_mode(rdev, mode); + if (err < 0) + rdev_err(rdev, "failed to set optimum mode %x\n", mode); } - err = rdev->desc->ops->set_mode(rdev, mode); - if (err < 0) - rdev_err(rdev, "failed to set optimum mode %x\n", mode); - return err; } diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d4ad5b5a02bb..8a0165f22f0a 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -98,6 +98,7 @@ struct regulator_linear_range { * REGULATOR_STATUS value (or negative errno) * @get_optimum_mode: Get the most efficient operating mode for the regulator * when running with the specified parameters. + * @set_load: Set the load for the regulator. * * @set_bypass: Set the regulator in bypass mode. * @get_bypass: Get the regulator bypass mode state. @@ -167,6 +168,8 @@ struct regulator_ops { /* get most efficient regulator operating mode for load */ unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, int output_uV, int load_uA); + /* set the load on the regulator */ + int (*set_load)(struct regulator_dev *, int load_uA); /* control and report on bypass mode */ int (*set_bypass)(struct regulator_dev *dev, bool enable); -- cgit v1.2.3 From b3f4737d00de317d1549d5cb5b1dad90e19f5cec Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 19 Feb 2015 15:33:56 -0800 Subject: HID: hid-sensor-hub: Extend API for async reads Add additional flag to read in async mode. In this mode the caller will get reply via registered callback for capture_sample. Callbacks can be registered using sensor_hub_register_callback function. The usage id parameter of the capture_sample can be matched with the usage id of the requested attribute. Signed-off-by: Srinivas Pandruvada Acked-by: Jonathan Cameron Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 65 ++++++++++++++------------- drivers/iio/accel/hid-sensor-accel-3d.c | 3 +- drivers/iio/gyro/hid-sensor-gyro-3d.c | 3 +- drivers/iio/light/hid-sensor-als.c | 3 +- drivers/iio/light/hid-sensor-prox.c | 3 +- drivers/iio/magnetometer/hid-sensor-magn-3d.c | 3 +- drivers/iio/orientation/hid-sensor-incl-3d.c | 3 +- drivers/iio/pressure/hid-sensor-press.c | 3 +- drivers/rtc/rtc-hid-sensor-time.c | 2 +- include/linux/hid-sensor-hub.h | 20 ++++++--- 10 files changed, 64 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index c325f85fa3a6..0a9162363164 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -250,48 +250,53 @@ EXPORT_SYMBOL_GPL(sensor_hub_get_feature); int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, u32 usage_id, - u32 attr_usage_id, u32 report_id) + u32 attr_usage_id, u32 report_id, + enum sensor_hub_read_flags flag) { struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); unsigned long flags; struct hid_report *report; int ret_val = 0; - mutex_lock(&hsdev->mutex); - memset(&hsdev->pending, 0, sizeof(hsdev->pending)); - init_completion(&hsdev->pending.ready); - hsdev->pending.usage_id = usage_id; - hsdev->pending.attr_usage_id = attr_usage_id; - hsdev->pending.raw_size = 0; - - spin_lock_irqsave(&data->lock, flags); - hsdev->pending.status = true; - spin_unlock_irqrestore(&data->lock, flags); - report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT); + report = sensor_hub_report(report_id, hsdev->hdev, + HID_INPUT_REPORT); if (!report) - goto err_free; + return -EINVAL; + mutex_lock(&hsdev->mutex); + if (flag == SENSOR_HUB_SYNC) { + memset(&hsdev->pending, 0, sizeof(hsdev->pending)); + init_completion(&hsdev->pending.ready); + hsdev->pending.usage_id = usage_id; + hsdev->pending.attr_usage_id = attr_usage_id; + hsdev->pending.raw_size = 0; + + spin_lock_irqsave(&data->lock, flags); + hsdev->pending.status = true; + spin_unlock_irqrestore(&data->lock, flags); + } mutex_lock(&data->mutex); hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); mutex_unlock(&data->mutex); - wait_for_completion_interruptible_timeout(&hsdev->pending.ready, HZ*5); - switch (hsdev->pending.raw_size) { - case 1: - ret_val = *(u8 *)hsdev->pending.raw_data; - break; - case 2: - ret_val = *(u16 *)hsdev->pending.raw_data; - break; - case 4: - ret_val = *(u32 *)hsdev->pending.raw_data; - break; - default: - ret_val = 0; + if (flag == SENSOR_HUB_SYNC) { + wait_for_completion_interruptible_timeout( + &hsdev->pending.ready, HZ*5); + switch (hsdev->pending.raw_size) { + case 1: + ret_val = *(u8 *)hsdev->pending.raw_data; + break; + case 2: + ret_val = *(u16 *)hsdev->pending.raw_data; + break; + case 4: + ret_val = *(u32 *)hsdev->pending.raw_data; + break; + default: + ret_val = 0; + } + kfree(hsdev->pending.raw_data); + hsdev->pending.status = false; } - kfree(hsdev->pending.raw_data); - -err_free: - hsdev->pending.status = false; mutex_unlock(&hsdev->mutex); return ret_val; diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index d5d95317003a..0085c2faeaaa 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -130,7 +130,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, *val = sensor_hub_input_attr_get_raw_value( accel_state->common_attributes.hsdev, HID_USAGE_SENSOR_ACCEL_3D, address, - report_id); + report_id, + SENSOR_HUB_SYNC); else { *val = 0; hid_sensor_power_state(&accel_state->common_attributes, diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index a3ea1e8785d7..bdcd105aba26 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -130,7 +130,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, *val = sensor_hub_input_attr_get_raw_value( gyro_state->common_attributes.hsdev, HID_USAGE_SENSOR_GYRO_3D, address, - report_id); + report_id, + SENSOR_HUB_SYNC); else { *val = 0; hid_sensor_power_state(&gyro_state->common_attributes, diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index a5283d75c096..321862da626b 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -109,7 +109,8 @@ static int als_read_raw(struct iio_dev *indio_dev, *val = sensor_hub_input_attr_get_raw_value( als_state->common_attributes.hsdev, HID_USAGE_SENSOR_ALS, address, - report_id); + report_id, + SENSOR_HUB_SYNC); hid_sensor_power_state(&als_state->common_attributes, false); } else { diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index f5a514698fd8..db9c60e47276 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -105,7 +105,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, *val = sensor_hub_input_attr_get_raw_value( prox_state->common_attributes.hsdev, HID_USAGE_SENSOR_PROX, address, - report_id); + report_id, + SENSOR_HUB_SYNC); hid_sensor_power_state(&prox_state->common_attributes, false); } else { diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 6294575d2777..4d299f39ffd1 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -178,7 +178,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, *val = sensor_hub_input_attr_get_raw_value( magn_state->common_attributes.hsdev, HID_USAGE_SENSOR_COMPASS_3D, address, - report_id); + report_id, + SENSOR_HUB_SYNC); else { *val = 0; hid_sensor_power_state(&magn_state->common_attributes, diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 1ff181bbbcef..45bed080b4a6 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -132,7 +132,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, *val = sensor_hub_input_attr_get_raw_value( incl_state->common_attributes.hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D, address, - report_id); + report_id, + SENSOR_HUB_SYNC); else { hid_sensor_power_state(&incl_state->common_attributes, false); diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 764928682df2..ac150f0c8b02 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -108,7 +108,8 @@ static int press_read_raw(struct iio_dev *indio_dev, *val = sensor_hub_input_attr_get_raw_value( press_state->common_attributes.hsdev, HID_USAGE_SENSOR_PRESSURE, address, - report_id); + report_id, + SENSOR_HUB_SYNC); hid_sensor_power_state(&press_state->common_attributes, false); } else { diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index ae7c2ba440cf..af4f85a66b39 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -213,7 +213,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) /* get a report with all values through requesting one value */ sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev, HID_USAGE_SENSOR_TIME, hid_time_addresses[0], - time_state->info[0].report_id); + time_state->info[0].report_id, SENSOR_HUB_SYNC); /* wait for all values (event) */ ret = wait_for_completion_killable_timeout( &time_state->comp_last_time, HZ*6); diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 60a34277ddf2..4c49b041922d 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -169,19 +169,27 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, struct hid_sensor_hub_attribute_info *info); /** -* sensor_hub_input_attr_get_raw_value() - Synchronous read request +* sensor_hub_input_attr_get_raw_value() - Attribute read request * @usage_id: Attribute usage id of parent physical device as per spec * @attr_usage_id: Attribute usage id as per spec * @report_id: Report id to look for +* @flag: Synchronous or asynchronous read * -* Issues a synchronous read request for an input attribute. Returns -* data upto 32 bits. Since client can get events, so this call should -* not be used for data paths, this will impact performance. +* Issues a synchronous or asynchronous read request for an input attribute. +* Returns data upto 32 bits. */ +enum sensor_hub_read_flags { + SENSOR_HUB_SYNC, + SENSOR_HUB_ASYNC, +}; + int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - u32 attr_usage_id, u32 report_id); + u32 usage_id, + u32 attr_usage_id, u32 report_id, + enum sensor_hub_read_flags flag +); + /** * sensor_hub_set_feature() - Feature set request * @report_id: Report id to look for -- cgit v1.2.3 From 6adc83fca74ab73abcbd3b394cf3a8fd3701db99 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 19 Feb 2015 15:35:25 -0800 Subject: HID: hid-sensor-hub: Enhance get feature report API Some hid sensor feature report can contain more than one reports. This API can now support receiving multiple values from the feature report. Also update the parameters in the users of this API. Signed-off-by: Srinivas Pandruvada Acked-by: Jonathan Cameron Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 15 +++++++++++++-- drivers/iio/common/hid-sensors/hid-sensor-attributes.c | 13 +++++++------ drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 4 ++-- include/linux/hid-sensor-hub.h | 8 +++++--- 4 files changed, 27 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 0a9162363164..c025c489270d 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -223,10 +223,11 @@ done_proc: EXPORT_SYMBOL_GPL(sensor_hub_set_feature); int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, - u32 field_index, s32 *value) + u32 field_index, int buffer_size, void *buffer) { struct hid_report *report; struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + int report_size; int ret = 0; mutex_lock(&data->mutex); @@ -238,7 +239,17 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, } hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); hid_hw_wait(hsdev->hdev); - *value = report->field[field_index]->value[0]; + + /* calculate number of bytes required to read this field */ + report_size = DIV_ROUND_UP(report->field[field_index]->report_size, + 8) * + report->field[field_index]->report_count; + if (!report_size) { + ret = -EINVAL; + goto done_proc; + } + ret = min(report_size, buffer_size); + memcpy(buffer, report->field[field_index]->value, ret); done_proc: mutex_unlock(&data->mutex); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 25b01e156d82..e1435e98636d 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -153,8 +153,8 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) int ret; ret = sensor_hub_get_feature(st->hsdev, - st->poll.report_id, - st->poll.index, &value); + st->poll.report_id, + st->poll.index, sizeof(value), &value); if (ret < 0 || value < 0) { return -EINVAL; @@ -174,8 +174,8 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, int ret; ret = sensor_hub_get_feature(st->hsdev, - st->poll.report_id, - st->poll.index, &value); + st->poll.report_id, + st->poll.index, sizeof(value), &value); if (ret < 0 || value < 0) { *val1 = *val2 = 0; return -EINVAL; @@ -229,8 +229,9 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, int ret; ret = sensor_hub_get_feature(st->hsdev, - st->sensitivity.report_id, - st->sensitivity.index, &value); + st->sensitivity.report_id, + st->sensitivity.index, sizeof(value), + &value); if (ret < 0 || value < 0) { *val1 = *val2 = 0; return -EINVAL; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 92068cdbf8c7..ef0c495a8ef9 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -76,8 +76,8 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state) } sensor_hub_get_feature(st->hsdev, st->power_state.report_id, - st->power_state.index, - &state_val); + st->power_state.index, + sizeof(state_val), &state_val); return 0; } EXPORT_SYMBOL(hid_sensor_power_state); diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 4c49b041922d..1db332066669 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -206,13 +206,15 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, * sensor_hub_get_feature() - Feature get request * @report_id: Report id to look for * @field_index: Field index inside a report -* @value: Place holder for return value +* @buffer_size: size of the buffer +* @buffer: buffer to copy output * * Used to get a field in feature report. For example this can get polling -* interval, sensitivity, activate/deactivate state. +* interval, sensitivity, activate/deactivate state. On success it returns +* number of bytes copied to buffer. On failure, it returns value < 0. */ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, - u32 field_index, s32 *value); + u32 field_index, int buffer_size, void *buffer); /* hid-sensor-attributes */ -- cgit v1.2.3 From 3950e03389cfc8ee9d7131074d999b5fb6bbc2bf Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 19 Feb 2015 15:35:26 -0800 Subject: HID: hid-sensor-hub: Enhance feature report set API Current API only allows setting one offset in the field. This API is extended to set multiple offsets in the field report. Also update parameters in the users of this API. Signed-off-by: Srinivas Pandruvada Reviewed-by: Jonathan Cameron Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 22 ++++++++++++++++++++-- .../iio/common/hid-sensors/hid-sensor-attributes.c | 11 +++++------ .../iio/common/hid-sensors/hid-sensor-trigger.c | 9 +++++---- include/linux/hid-sensor-hub.h | 5 +++-- 4 files changed, 33 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index c025c489270d..44da796fa4fd 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -199,10 +199,14 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, EXPORT_SYMBOL_GPL(sensor_hub_remove_callback); int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, - u32 field_index, s32 value) + u32 field_index, int buffer_size, void *buffer) { struct hid_report *report; struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + __s32 *buf32 = buffer; + int i = 0; + int remaining_bytes; + __s32 value; int ret = 0; mutex_lock(&data->mutex); @@ -211,7 +215,21 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, ret = -EINVAL; goto done_proc; } - hid_set_field(report->field[field_index], 0, value); + + remaining_bytes = do_div(buffer_size, sizeof(__s32)); + if (buffer_size) { + for (i = 0; i < buffer_size; ++i) { + hid_set_field(report->field[field_index], i, + cpu_to_le32(*buf32)); + ++buf32; + } + } + if (remaining_bytes) { + value = 0; + memcpy(&value, (u8 *)buf32, remaining_bytes); + hid_set_field(report->field[field_index], i, + cpu_to_le32(value)); + } hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT); hid_hw_wait(hsdev->hdev); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index e1435e98636d..e81f434760f4 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -212,9 +212,8 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, else value = 0; } - ret = sensor_hub_set_feature(st->hsdev, - st->poll.report_id, - st->poll.index, value); + ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id, + st->poll.index, sizeof(value), &value); if (ret < 0 || value < 0) ret = -EINVAL; @@ -254,9 +253,9 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, value = convert_to_vtf_format(st->sensitivity.size, st->sensitivity.unit_expo, val1, val2); - ret = sensor_hub_set_feature(st->hsdev, - st->sensitivity.report_id, - st->sensitivity.index, value); + ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id, + st->sensitivity.index, sizeof(value), + &value); if (ret < 0 || value < 0) ret = -EINVAL; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index ef0c495a8ef9..910e82a7d06e 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -64,15 +64,16 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state) if (state_val >= 0) { state_val += st->power_state.logical_minimum; sensor_hub_set_feature(st->hsdev, st->power_state.report_id, - st->power_state.index, - (s32)state_val); + st->power_state.index, sizeof(state_val), + &state_val); } if (report_val >= 0) { report_val += st->report_state.logical_minimum; sensor_hub_set_feature(st->hsdev, st->report_state.report_id, - st->report_state.index, - (s32)report_val); + st->report_state.index, + sizeof(report_val), + &report_val); } sensor_hub_get_feature(st->hsdev, st->power_state.report_id, diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 1db332066669..4a2fdbabfcf1 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -194,13 +194,14 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, * sensor_hub_set_feature() - Feature set request * @report_id: Report id to look for * @field_index: Field index inside a report -* @value: Value to set +* @buffer_size: size of the buffer +* @buffer: buffer to use in the feature set * * Used to set a field in feature report. For example this can set polling * interval, sensitivity, activate/deactivate state. */ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, - u32 field_index, s32 value); + u32 field_index, int buffer_size, void *buffer); /** * sensor_hub_get_feature() - Feature get request -- cgit v1.2.3 From 052a9f698268e606ca01eb1ce2a672e548f2ce11 Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Mon, 9 Feb 2015 00:18:11 -0800 Subject: ALSA: Add params_set_format helper Add a helper to set pcm format directly from params Signed-off-by: Fang, Yang A Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/pcm_params.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 3c45f3924ba7..c704357775fc 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p) return snd_pcm_format_physical_width(params_format(p)); } +static inline void +params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt) +{ + snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), + (__force int)fmt); +} + #endif /* __SOUND_PCM_PARAMS_H */ -- cgit v1.2.3 From 48c7699fb2c799d084ce490bceea14fe04ad12a1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 12 Feb 2015 09:59:53 +0530 Subject: ASoC: core: allow pcms to be registered as nonatomic ALSA core with commit 257f8cce5d40 - "ALSA: pcm: Allow nonatomic trigger operations" allows trigger ops to implemented as nonatomic. For ASoC, we can specify this in dailinks and is updated while snd_pcm is created Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Cc: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/soc-pcm.c | 1 + 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..76bc944dcb5c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -954,6 +954,9 @@ struct snd_soc_dai_link { unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; + /* Mark this pcm with non atomic ops */ + bool nonatomic; + /* Do not create a PCM for this DAI link (Backend link) */ unsigned int no_pcm:1; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6b0136e7cb88..6e3781e88f9a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2511,6 +2511,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); + pcm->nonatomic = rtd->dai_link->nonatomic; rtd->pcm = pcm; pcm->private_data = rtd; -- cgit v1.2.3 From 1aee41f637694d4bbf91c24195f2b63e3f6badd2 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Wed, 29 Oct 2014 18:51:31 -0500 Subject: Add new disk to clustered array Algorithm: 1. Node 1 issues mdadm --manage /dev/mdX --add /dev/sdYY which issues ioctl(ADD_NEW_DISC with disc.state set to MD_DISK_CLUSTER_ADD) 2. Node 1 sends NEWDISK with uuid and slot number 3. Other nodes issue kobject_uevent_env with uuid and slot number (Steps 4,5 could be a udev rule) 4. In userspace, the node searches for the disk, perhaps using blkid -t SUB_UUID="" 5. Other nodes issue either of the following depending on whether the disk was found: ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CANDIDATE and disc.number set to slot number) ioctl(CLUSTERED_DISK_NACK) 6. Other nodes drop lock on no-new-devs (CR) if device is found 7. Node 1 attempts EX lock on no-new-devs 8. If node 1 gets the lock, it sends METADATA_UPDATED after unmarking the disk as SpareLocal 9. If not (get no-new-dev lock), it fails the operation and sends METADATA_UPDATED 10. Other nodes understand if the device is added or not by reading the superblock again after receiving the METADATA_UPDATED message. Signed-off-by: Lidong Zhong Signed-off-by: Goldwyn Rodrigues --- drivers/md/md-cluster.c | 104 ++++++++++++++++++++++++++++++++++++++++- drivers/md/md-cluster.h | 4 ++ drivers/md/md.c | 52 +++++++++++++++++++-- drivers/md/md.h | 5 ++ drivers/md/raid1.c | 1 + include/uapi/linux/raid/md_p.h | 6 +++ include/uapi/linux/raid/md_u.h | 1 + 7 files changed, 169 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index d85a6ca4443e..03e521a9ca7d 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -12,11 +12,13 @@ #include #include #include +#include #include "md.h" #include "bitmap.h" #include "md-cluster.h" #define LVB_SIZE 64 +#define NEW_DEV_TIMEOUT 5000 struct dlm_lock_resource { dlm_lockspace_t *ls; @@ -56,19 +58,25 @@ struct md_cluster_info { struct dlm_lock_resource *ack_lockres; struct dlm_lock_resource *message_lockres; struct dlm_lock_resource *token_lockres; + struct dlm_lock_resource *no_new_dev_lockres; struct md_thread *recv_thread; + struct completion newdisk_completion; }; enum msg_type { METADATA_UPDATED = 0, RESYNCING, + NEWDISK, }; struct cluster_msg { int type; int slot; + /* TODO: Unionize this for smaller footprint */ sector_t low; sector_t high; + char uuid[16]; + int raid_slot; }; static void sync_ast(void *arg) @@ -358,13 +366,41 @@ static void process_suspend_info(struct md_cluster_info *cinfo, spin_unlock_irq(&cinfo->suspend_lock); } +static void process_add_new_disk(struct mddev *mddev, struct cluster_msg *cmsg) +{ + char disk_uuid[64]; + struct md_cluster_info *cinfo = mddev->cluster_info; + char event_name[] = "EVENT=ADD_DEVICE"; + char raid_slot[16]; + char *envp[] = {event_name, disk_uuid, raid_slot, NULL}; + int len; + + len = snprintf(disk_uuid, 64, "DEVICE_UUID="); + pretty_uuid(disk_uuid + len, cmsg->uuid); + snprintf(raid_slot, 16, "RAID_DISK=%d", cmsg->raid_slot); + pr_info("%s:%d Sending kobject change with %s and %s\n", __func__, __LINE__, disk_uuid, raid_slot); + init_completion(&cinfo->newdisk_completion); + kobject_uevent_env(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE, envp); + wait_for_completion_timeout(&cinfo->newdisk_completion, + NEW_DEV_TIMEOUT); +} + + +static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + + md_reload_sb(mddev); + dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR); +} + static void process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg) { switch (msg->type) { case METADATA_UPDATED: pr_info("%s: %d Received message: METADATA_UPDATE from %d\n", __func__, __LINE__, msg->slot); - md_reload_sb(mddev); + process_metadata_update(mddev, msg); break; case RESYNCING: pr_info("%s: %d Received message: RESYNCING from %d\n", @@ -372,6 +408,10 @@ static void process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg) process_suspend_info(mddev->cluster_info, msg->slot, msg->low, msg->high); break; + case NEWDISK: + pr_info("%s: %d Received message: NEWDISK from %d\n", + __func__, __LINE__, msg->slot); + process_add_new_disk(mddev, msg); }; } @@ -593,10 +633,18 @@ static int join(struct mddev *mddev, int nodes) cinfo->ack_lockres = lockres_init(mddev, "ack", ack_bast, 0); if (!cinfo->ack_lockres) goto err; + cinfo->no_new_dev_lockres = lockres_init(mddev, "no-new-dev", NULL, 0); + if (!cinfo->no_new_dev_lockres) + goto err; + /* get sync CR lock on ACK. */ if (dlm_lock_sync(cinfo->ack_lockres, DLM_LOCK_CR)) pr_err("md-cluster: failed to get a sync CR lock on ACK!(%d)\n", ret); + /* get sync CR lock on no-new-dev. */ + if (dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR)) + pr_err("md-cluster: failed to get a sync CR lock on no-new-dev!(%d)\n", ret); + pr_info("md-cluster: Joined cluster %s slot %d\n", str, cinfo->slot_number); snprintf(str, 64, "bitmap%04d", cinfo->slot_number - 1); @@ -621,6 +669,7 @@ err: lockres_free(cinfo->message_lockres); lockres_free(cinfo->token_lockres); lockres_free(cinfo->ack_lockres); + lockres_free(cinfo->no_new_dev_lockres); lockres_free(cinfo->bitmap_lockres); lockres_free(cinfo->sb_lock); if (cinfo->lockspace) @@ -642,6 +691,7 @@ static int leave(struct mddev *mddev) lockres_free(cinfo->message_lockres); lockres_free(cinfo->token_lockres); lockres_free(cinfo->ack_lockres); + lockres_free(cinfo->no_new_dev_lockres); lockres_free(cinfo->sb_lock); lockres_free(cinfo->bitmap_lockres); dlm_release_lockspace(cinfo->lockspace, 2); @@ -742,6 +792,55 @@ out: return ret; } +static int add_new_disk_start(struct mddev *mddev, struct md_rdev *rdev) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + struct cluster_msg cmsg; + int ret = 0; + struct mdp_superblock_1 *sb = page_address(rdev->sb_page); + char *uuid = sb->device_uuid; + + memset(&cmsg, 0, sizeof(cmsg)); + cmsg.type = cpu_to_le32(NEWDISK); + memcpy(cmsg.uuid, uuid, 16); + cmsg.raid_slot = rdev->desc_nr; + lock_comm(cinfo); + ret = __sendmsg(cinfo, &cmsg); + if (ret) + return ret; + cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE; + ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX); + cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE; + /* Some node does not "see" the device */ + if (ret == -EAGAIN) + ret = -ENOENT; + else + dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR); + return ret; +} + +static int add_new_disk_finish(struct mddev *mddev) +{ + struct cluster_msg cmsg; + struct md_cluster_info *cinfo = mddev->cluster_info; + int ret; + /* Write sb and inform others */ + md_update_sb(mddev, 1); + cmsg.type = METADATA_UPDATED; + ret = __sendmsg(cinfo, &cmsg); + unlock_comm(cinfo); + return ret; +} + +static void new_disk_ack(struct mddev *mddev, bool ack) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + + if (ack) + dlm_unlock_sync(cinfo->no_new_dev_lockres); + complete(&cinfo->newdisk_completion); +} + static struct md_cluster_operations cluster_ops = { .join = join, .leave = leave, @@ -753,6 +852,9 @@ static struct md_cluster_operations cluster_ops = { .metadata_update_finish = metadata_update_finish, .metadata_update_cancel = metadata_update_cancel, .area_resyncing = area_resyncing, + .add_new_disk_start = add_new_disk_start, + .add_new_disk_finish = add_new_disk_finish, + .new_disk_ack = new_disk_ack, }; static int __init cluster_init(void) diff --git a/drivers/md/md-cluster.h b/drivers/md/md-cluster.h index 03785402afaa..60d7e58964f5 100644 --- a/drivers/md/md-cluster.h +++ b/drivers/md/md-cluster.h @@ -6,6 +6,7 @@ #include "md.h" struct mddev; +struct md_rdev; struct md_cluster_operations { int (*join)(struct mddev *mddev, int nodes); @@ -18,6 +19,9 @@ struct md_cluster_operations { int (*metadata_update_finish)(struct mddev *mddev); int (*metadata_update_cancel)(struct mddev *mddev); int (*area_resyncing)(struct mddev *mddev, sector_t lo, sector_t hi); + int (*add_new_disk_start)(struct mddev *mddev, struct md_rdev *rdev); + int (*add_new_disk_finish)(struct mddev *mddev); + void (*new_disk_ack)(struct mddev *mddev, bool ack); }; #endif /* _MD_CLUSTER_H */ diff --git a/drivers/md/md.c b/drivers/md/md.c index fe0484648de4..5703c2e89f3a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2210,7 +2210,7 @@ static void sync_sbs(struct mddev *mddev, int nospares) } } -static void md_update_sb(struct mddev *mddev, int force_change) +void md_update_sb(struct mddev *mddev, int force_change) { struct md_rdev *rdev; int sync_req; @@ -2371,6 +2371,7 @@ repeat: wake_up(&rdev->blocked_wait); } } +EXPORT_SYMBOL(md_update_sb); /* words written to sysfs files may, or may not, be \n terminated. * We want to accept with case. For this we use cmd_match. @@ -3151,7 +3152,7 @@ static void analyze_sbs(struct mddev *mddev) kick_rdev_from_array(rdev); continue; } - if (rdev != freshest) + if (rdev != freshest) { if (super_types[mddev->major_version]. validate_super(mddev, rdev)) { printk(KERN_WARNING "md: kicking non-fresh %s" @@ -3160,6 +3161,15 @@ static void analyze_sbs(struct mddev *mddev) kick_rdev_from_array(rdev); continue; } + /* No device should have a Candidate flag + * when reading devices + */ + if (test_bit(Candidate, &rdev->flags)) { + pr_info("md: kicking Cluster Candidate %s from array!\n", + bdevname(rdev->bdev, b)); + kick_rdev_from_array(rdev); + } + } if (mddev->level == LEVEL_MULTIPATH) { rdev->desc_nr = i++; rdev->raid_disk = rdev->desc_nr; @@ -5655,7 +5665,6 @@ static int get_array_info(struct mddev *mddev, void __user *arg) info.state |= (1<major,info->minor); + if (mddev_is_clustered(mddev) && + !(info->state & ((1 << MD_DISK_CLUSTER_ADD) | (1 << MD_DISK_CANDIDATE)))) { + pr_err("%s: Cannot add to clustered mddev. Try --cluster-add\n", + mdname(mddev)); + return -EINVAL; + } + if (info->major != MAJOR(dev) || info->minor != MINOR(dev)) return -EOVERFLOW; @@ -5830,6 +5846,25 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info) else clear_bit(WriteMostly, &rdev->flags); + /* + * check whether the device shows up in other nodes + */ + if (mddev_is_clustered(mddev)) { + if (info->state & (1 << MD_DISK_CANDIDATE)) { + /* Through --cluster-confirm */ + set_bit(Candidate, &rdev->flags); + md_cluster_ops->new_disk_ack(mddev, true); + } else if (info->state & (1 << MD_DISK_CLUSTER_ADD)) { + /* --add initiated by this node */ + err = md_cluster_ops->add_new_disk_start(mddev, rdev); + if (err) { + md_cluster_ops->add_new_disk_finish(mddev); + export_rdev(rdev); + return err; + } + } + } + rdev->raid_disk = -1; err = bind_rdev_to_array(rdev, mddev); if (!err && !mddev->pers->hot_remove_disk) { @@ -5855,6 +5890,9 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info) if (!err) md_new_event(mddev); md_wakeup_thread(mddev->thread); + if (mddev_is_clustered(mddev) && + (info->state & (1 << MD_DISK_CLUSTER_ADD))) + md_cluster_ops->add_new_disk_finish(mddev); return err; } @@ -6456,6 +6494,7 @@ static inline bool md_ioctl_valid(unsigned int cmd) case SET_DISK_FAULTY: case STOP_ARRAY: case STOP_ARRAY_RO: + case CLUSTERED_DISK_NACK: return true; default: return false; @@ -6728,6 +6767,13 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, goto unlock; } + case CLUSTERED_DISK_NACK: + if (mddev_is_clustered(mddev)) + md_cluster_ops->new_disk_ack(mddev, false); + else + err = -EINVAL; + goto unlock; + case HOT_ADD_DISK: err = hot_add_disk(mddev, new_decode_dev(arg)); goto unlock; diff --git a/drivers/md/md.h b/drivers/md/md.h index bfebcfdf54e6..6dc0ce09f50c 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -171,6 +171,10 @@ enum flag_bits { * a want_replacement device with same * raid_disk number. */ + Candidate, /* For clustered environments only: + * This device is seen locally but not + * by the whole cluster + */ }; #define BB_LEN_MASK (0x00000000000001FFULL) @@ -666,6 +670,7 @@ extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, extern void md_unplug(struct blk_plug_cb *cb, bool from_schedule); extern void md_reload_sb(struct mddev *mddev); +extern void md_update_sb(struct mddev *mddev, int force); static inline int mddev_check_plugged(struct mddev *mddev) { return !!blk_check_plugged(md_unplug, mddev, diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f70d74189d16..53ed5d48308f 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1571,6 +1571,7 @@ static int raid1_spare_active(struct mddev *mddev) struct md_rdev *rdev = conf->mirrors[i].rdev; struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev; if (repl + && !test_bit(Candidate, &repl->flags) && repl->recovery_offset == MaxSector && !test_bit(Faulty, &repl->flags) && !test_and_set_bit(In_sync, &repl->flags)) { diff --git a/include/uapi/linux/raid/md_p.h b/include/uapi/linux/raid/md_p.h index 643489d33e68..2ae6131e69a5 100644 --- a/include/uapi/linux/raid/md_p.h +++ b/include/uapi/linux/raid/md_p.h @@ -78,6 +78,12 @@ #define MD_DISK_ACTIVE 1 /* disk is running or spare disk */ #define MD_DISK_SYNC 2 /* disk is in sync with the raid set */ #define MD_DISK_REMOVED 3 /* disk is in sync with the raid set */ +#define MD_DISK_CLUSTER_ADD 4 /* Initiate a disk add across the cluster + * For clustered enviroments only. + */ +#define MD_DISK_CANDIDATE 5 /* disk is added as spare (local) until confirmed + * For clustered enviroments only. + */ #define MD_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config. * read requests will only be sent here in diff --git a/include/uapi/linux/raid/md_u.h b/include/uapi/linux/raid/md_u.h index 74e7c60c4716..1cb8aa6850b5 100644 --- a/include/uapi/linux/raid/md_u.h +++ b/include/uapi/linux/raid/md_u.h @@ -62,6 +62,7 @@ #define STOP_ARRAY _IO (MD_MAJOR, 0x32) #define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33) #define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34) +#define CLUSTERED_DISK_NACK _IO (MD_MAJOR, 0x35) /* 63 partitions with the alternate major number (mdp) */ #define MdpMinorShift 6 -- cgit v1.2.3 From fdfd811ddde3678247248ca9a27faa999ca4cd51 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 19 Feb 2015 15:23:17 +0000 Subject: x86/xen: allow privcmd hypercalls to be preempted Hypercalls submitted by user space tools via the privcmd driver can take a long time (potentially many 10s of seconds) if the hypercall has many sub-operations. A fully preemptible kernel may deschedule such as task in any upcall called from a hypercall continuation. However, in a kernel with voluntary or no preemption, hypercall continuations in Xen allow event handlers to be run but the task issuing the hypercall will not be descheduled until the hypercall is complete and the ioctl returns to user space. These long running tasks may also trigger the kernel's soft lockup detection. Add xen_preemptible_hcall_begin() and xen_preemptible_hcall_end() to bracket hypercalls that may be preempted. Use these in the privcmd driver. When returning from an upcall, call xen_maybe_preempt_hcall() which adds a schedule point if if the current task was within a preemptible hypercall. Since _cond_resched() can move the task to a different CPU, clear and set xen_in_preemptible_hcall around the call. Signed-off-by: David Vrabel Reviewed-by: Boris Ostrovsky --- arch/x86/kernel/entry_32.S | 3 +++ arch/x86/kernel/entry_64.S | 3 +++ drivers/xen/Makefile | 2 +- drivers/xen/preempt.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ drivers/xen/privcmd.c | 2 ++ include/xen/xen-ops.h | 26 ++++++++++++++++++++++++++ 6 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 drivers/xen/preempt.c (limited to 'include') diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 000d4199b03e..31e2d5bf3e38 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -982,6 +982,9 @@ ENTRY(xen_hypervisor_callback) ENTRY(xen_do_upcall) 1: mov %esp, %eax call xen_evtchn_do_upcall +#ifndef CONFIG_PREEMPT + call xen_maybe_preempt_hcall +#endif jmp ret_from_intr CFI_ENDPROC ENDPROC(xen_hypervisor_callback) diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index db13655c3a2a..10074ad9ebf8 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -1208,6 +1208,9 @@ ENTRY(xen_do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs) popq %rsp CFI_DEF_CFA_REGISTER rsp decl PER_CPU_VAR(irq_count) +#ifndef CONFIG_PREEMPT + call xen_maybe_preempt_hcall +#endif jmp error_exit CFI_ENDPROC END(xen_do_hypervisor_callback) diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 2140398a2a8c..2ccd3592d41f 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -2,7 +2,7 @@ ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),) obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o endif obj-$(CONFIG_X86) += fallback.o -obj-y += grant-table.o features.o balloon.o manage.o +obj-y += grant-table.o features.o balloon.o manage.o preempt.o obj-y += events/ obj-y += xenbus/ diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c new file mode 100644 index 000000000000..a1800c150839 --- /dev/null +++ b/drivers/xen/preempt.c @@ -0,0 +1,44 @@ +/* + * Preemptible hypercalls + * + * Copyright (C) 2014 Citrix Systems R&D ltd. + * + * This source code 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 +#include + +#ifndef CONFIG_PREEMPT + +/* + * Some hypercalls issued by the toolstack can take many 10s of + * seconds. Allow tasks running hypercalls via the privcmd driver to + * be voluntarily preempted even if full kernel preemption is + * disabled. + * + * Such preemptible hypercalls are bracketed by + * xen_preemptible_hcall_begin() and xen_preemptible_hcall_end() + * calls. + */ + +DEFINE_PER_CPU(bool, xen_in_preemptible_hcall); +EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall); + +asmlinkage __visible void xen_maybe_preempt_hcall(void) +{ + if (unlikely(__this_cpu_read(xen_in_preemptible_hcall) + && should_resched())) { + /* + * Clear flag as we may be rescheduled on a different + * cpu. + */ + __this_cpu_write(xen_in_preemptible_hcall, false); + _cond_resched(); + __this_cpu_write(xen_in_preemptible_hcall, true); + } +} +#endif /* CONFIG_PREEMPT */ diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 569a13b9e856..59ac71c4a043 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -56,10 +56,12 @@ static long privcmd_ioctl_hypercall(void __user *udata) if (copy_from_user(&hypercall, udata, sizeof(hypercall))) return -EFAULT; + xen_preemptible_hcall_begin(); ret = privcmd_call(hypercall.op, hypercall.arg[0], hypercall.arg[1], hypercall.arg[2], hypercall.arg[3], hypercall.arg[4]); + xen_preemptible_hcall_end(); return ret; } diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 7491ee5d8164..83338210ee04 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -46,4 +46,30 @@ static inline efi_system_table_t __init *xen_efi_probe(void) } #endif +#ifdef CONFIG_PREEMPT + +static inline void xen_preemptible_hcall_begin(void) +{ +} + +static inline void xen_preemptible_hcall_end(void) +{ +} + +#else + +DECLARE_PER_CPU(bool, xen_in_preemptible_hcall); + +static inline void xen_preemptible_hcall_begin(void) +{ + __this_cpu_write(xen_in_preemptible_hcall, true); +} + +static inline void xen_preemptible_hcall_end(void) +{ + __this_cpu_write(xen_in_preemptible_hcall, false); +} + +#endif /* CONFIG_PREEMPT */ + #endif /* INCLUDE_XEN_OPS_H */ -- cgit v1.2.3 From 56a215d66b1eee870a6b90a8c245dfc3e503a137 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 6 Jan 2015 20:56:05 +0100 Subject: ARM: shmobile: sh73a0 dtsi: Add missing INTCA0 clock for irqpin module This clock drives the irqpin controller modules. Before, it was assumed enabled by the bootloader or reset state. By making it available to the driver, we make sure it gets enabled when needed, and allow it to be managed by system or runtime PM. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/sh73a0.dtsi | 15 +++++++++++++++ include/dt-bindings/clock/sh73a0-clock.h | 3 +++ 2 files changed, 18 insertions(+) (limited to 'include') diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi index 076708797ef6..08f736d52179 100644 --- a/arch/arm/boot/dts/sh73a0.dtsi +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -94,6 +94,7 @@ 0 6 IRQ_TYPE_LEVEL_HIGH 0 7 IRQ_TYPE_LEVEL_HIGH 0 8 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -114,6 +115,7 @@ 0 14 IRQ_TYPE_LEVEL_HIGH 0 15 IRQ_TYPE_LEVEL_HIGH 0 16 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -134,6 +136,7 @@ 0 22 IRQ_TYPE_LEVEL_HIGH 0 23 IRQ_TYPE_LEVEL_HIGH 0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -154,6 +157,7 @@ 0 30 IRQ_TYPE_LEVEL_HIGH 0 31 IRQ_TYPE_LEVEL_HIGH 0 32 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -698,5 +702,16 @@ clock-output-names = "iic3", "iic4", "keysc"; }; + mstp5_clks: mstp5_clks@e6150144 { + compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks"; + reg = <0xe6150144 4>, <0xe615003c 4>; + clocks = <&cpg_clocks SH73A0_CLK_HP>; + #clock-cells = <1>; + clock-indices = < + SH73A0_CLK_INTCA0 + >; + clock-output-names = + "intca0"; + }; }; }; diff --git a/include/dt-bindings/clock/sh73a0-clock.h b/include/dt-bindings/clock/sh73a0-clock.h index 1dd3eb2b7d90..53369568c24c 100644 --- a/include/dt-bindings/clock/sh73a0-clock.h +++ b/include/dt-bindings/clock/sh73a0-clock.h @@ -76,4 +76,7 @@ #define SH73A0_CLK_IIC4 10 #define SH73A0_CLK_KEYSC 3 +/* MSTP5 */ +#define SH73A0_CLK_INTCA0 8 + #endif -- cgit v1.2.3 From 41650f406cdc4a420d5c08e1b407f6420323a04b Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 6 Jan 2015 00:33:25 +0300 Subject: ARM: shmobile: r8a7790: add CAN clocks The R-Car CAN controllers can derive the CAN bus clock not only from their peripheral clock input (clkp1) but also from the other internal clock (clkp2) and external clock fed on CAN_CLK pin. Describe those clocks in the device tree, along with the USB_EXTAL clock from which clkp2 is derived. Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 22 ++++++++++++++++++++-- include/dt-bindings/clock/r8a7790-clock.h | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 24de994443e1..e872854b4ba9 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -838,16 +838,34 @@ clock-output-names = "audio_clk_c"; }; + /* External USB clock - can be overridden by the board */ + usb_extal_clk: usb_extal_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + clock-output-names = "usb_extal"; + }; + + /* External CAN clock */ + can_clk: can_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + clock-output-names = "can_clk"; + status = "disabled"; + }; + /* Special CPG clocks */ cpg_clocks: cpg_clocks@e6150000 { compatible = "renesas,r8a7790-cpg-clocks", "renesas,rcar-gen2-cpg-clocks"; reg = <0 0xe6150000 0 0x1000>; - clocks = <&extal_clk>; + clocks = <&extal_clk &usb_extal_clk>; #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", - "z"; + "z", "rcan"; }; /* Variable factor clocks */ diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index 91940271cf83..ffa8c11be68a 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -21,6 +21,7 @@ #define R8A7790_CLK_SD0 7 #define R8A7790_CLK_SD1 8 #define R8A7790_CLK_Z 9 +#define R8A7790_CLK_RCAN 10 /* MSTP0 */ #define R8A7790_CLK_MSIOF0 0 -- cgit v1.2.3 From b324252cc18d52d5752942a8574c22229153c58f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 6 Jan 2015 01:24:08 +0300 Subject: ARM: shmobile: r8a7791: add CAN clocks The R-Car CAN controllers can derive the CAN bus clock not only from their peripheral clock input (clkp1) but also from the other internal clock (clkp2) and external clock fed on CAN_CLK pin. Describe those clocks in the device tree, along with the USB_EXTAL clock from which clkp2 is derived. Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 23 +++++++++++++++++++++-- include/dt-bindings/clock/r8a7791-clock.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index afba8af1a5e4..1ebffef5b908 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -862,15 +862,34 @@ status = "disabled"; }; + /* External USB clock - can be overridden by the board */ + usb_extal_clk: usb_extal_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + clock-output-names = "usb_extal"; + }; + + /* External CAN clock */ + can_clk: can_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + clock-output-names = "can_clk"; + status = "disabled"; + }; + /* Special CPG clocks */ cpg_clocks: cpg_clocks@e6150000 { compatible = "renesas,r8a7791-cpg-clocks", "renesas,rcar-gen2-cpg-clocks"; reg = <0 0xe6150000 0 0x1000>; - clocks = <&extal_clk>; + clocks = <&extal_clk &usb_extal_clk>; #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", - "lb", "qspi", "sdh", "sd0", "z"; + "lb", "qspi", "sdh", "sd0", "z", + "rcan"; }; /* Variable factor clocks */ diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h index f096f3f6c16a..a45a36307895 100644 --- a/include/dt-bindings/clock/r8a7791-clock.h +++ b/include/dt-bindings/clock/r8a7791-clock.h @@ -20,6 +20,7 @@ #define R8A7791_CLK_SDH 6 #define R8A7791_CLK_SD0 7 #define R8A7791_CLK_Z 8 +#define R8A7791_CLK_RCAN 9 /* MSTP0 */ #define R8A7791_CLK_MSIOF0 0 -- cgit v1.2.3 From ae65a8ae4c25c7ea01204c9d033cd47da3000cf8 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 30 Dec 2014 23:20:34 +0300 Subject: ARM: shmobile: r8a7791: add ADSP clocks Add the ADSP clocks to the CPG and MSTP5 nodes of the R8A7791 device tree. Based on the original patch by Konstantin Kozhevnikov . Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 11 +++++++---- include/dt-bindings/clock/r8a7791-clock.h | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index ff49b95df0ec..1e593a2b55fa 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -909,7 +909,7 @@ #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "z", - "rcan"; + "rcan", "adsp"; }; /* Variable factor clocks */ @@ -1164,13 +1164,16 @@ mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>; - clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>; + clocks = <&hp_clk>, <&hp_clk>, <&cpg_clocks R8A7791_CLK_ADSP>, + <&extal_clk>, <&p_clk>; #clock-cells = <1>; clock-indices = < R8A7791_CLK_AUDIO_DMAC0 R8A7791_CLK_AUDIO_DMAC1 - R8A7791_CLK_THERMAL R8A7791_CLK_PWM + R8A7791_CLK_ADSP_MOD R8A7791_CLK_THERMAL + R8A7791_CLK_PWM >; - clock-output-names = "audmac0", "audmac1", "thermal", "pwm"; + clock-output-names = "audmac0", "audmac1", "adsp_mod", + "thermal", "pwm"; }; mstp7_clks: mstp7_clks@e615014c { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h index a45a36307895..8fc5dc8faeea 100644 --- a/include/dt-bindings/clock/r8a7791-clock.h +++ b/include/dt-bindings/clock/r8a7791-clock.h @@ -21,6 +21,7 @@ #define R8A7791_CLK_SD0 7 #define R8A7791_CLK_Z 8 #define R8A7791_CLK_RCAN 9 +#define R8A7791_CLK_ADSP 10 /* MSTP0 */ #define R8A7791_CLK_MSIOF0 0 @@ -72,6 +73,7 @@ /* MSTP5 */ #define R8A7791_CLK_AUDIO_DMAC1 1 #define R8A7791_CLK_AUDIO_DMAC0 2 +#define R8A7791_CLK_ADSP_MOD 6 #define R8A7791_CLK_THERMAL 22 #define R8A7791_CLK_PWM 23 -- cgit v1.2.3 From 3453ca9e4f51a0e6865d303f4e428cb6f630594f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 30 Dec 2014 23:21:45 +0300 Subject: ARM: shmobile: r8a7790: add ADSP clocks Add the ADSP clocks to the CPG and MSTP5 nodes of the R8A7790 device tree. Based on the original patch by Konstantin Kozhevnikov . Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 11 +++++++---- include/dt-bindings/clock/r8a7790-clock.h | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index cd7fc05f5e99..c6c0a0c8f1be 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -885,7 +885,7 @@ #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", - "z", "rcan"; + "z", "rcan", "adsp"; }; /* Variable factor clocks */ @@ -1159,13 +1159,16 @@ mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>; - clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>; + clocks = <&hp_clk>, <&hp_clk>, <&cpg_clocks R8A7790_CLK_ADSP>, + <&extal_clk>, <&p_clk>; #clock-cells = <1>; clock-indices = < R8A7790_CLK_AUDIO_DMAC0 R8A7790_CLK_AUDIO_DMAC1 - R8A7790_CLK_THERMAL R8A7790_CLK_PWM + R8A7790_CLK_ADSP_MOD R8A7790_CLK_THERMAL + R8A7790_CLK_PWM >; - clock-output-names = "audmac0", "audmac1", "thermal", "pwm"; + clock-output-names = "audmac0", "audmac1", "adsp_mod", + "thermal", "pwm"; }; mstp7_clks: mstp7_clks@e615014c { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index ffa8c11be68a..3f2c6b198d4a 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -22,6 +22,7 @@ #define R8A7790_CLK_SD1 8 #define R8A7790_CLK_Z 9 #define R8A7790_CLK_RCAN 10 +#define R8A7790_CLK_ADSP 11 /* MSTP0 */ #define R8A7790_CLK_MSIOF0 0 @@ -81,6 +82,7 @@ /* MSTP5 */ #define R8A7790_CLK_AUDIO_DMAC1 1 #define R8A7790_CLK_AUDIO_DMAC0 2 +#define R8A7790_CLK_ADSP_MOD 6 #define R8A7790_CLK_THERMAL 22 #define R8A7790_CLK_PWM 23 -- cgit v1.2.3 From bdba0101c7e90e60481018005654227bdfd67aec Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 20 Jan 2015 13:51:38 +0100 Subject: ARM: shmobile: r8a73a4: Add CPG register bits header Signed-off-by: Ulrich Hecht Acked-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- include/dt-bindings/clock/r8a73a4-clock.h | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 include/dt-bindings/clock/r8a73a4-clock.h (limited to 'include') diff --git a/include/dt-bindings/clock/r8a73a4-clock.h b/include/dt-bindings/clock/r8a73a4-clock.h new file mode 100644 index 000000000000..9a4b4c9ca44a --- /dev/null +++ b/include/dt-bindings/clock/r8a73a4-clock.h @@ -0,0 +1,62 @@ +/* + * Copyright 2014 Ulrich Hecht + * + * 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 __DT_BINDINGS_CLOCK_R8A73A4_H__ +#define __DT_BINDINGS_CLOCK_R8A73A4_H__ + +/* CPG */ +#define R8A73A4_CLK_MAIN 0 +#define R8A73A4_CLK_PLL0 1 +#define R8A73A4_CLK_PLL1 2 +#define R8A73A4_CLK_PLL2 3 +#define R8A73A4_CLK_PLL2S 4 +#define R8A73A4_CLK_PLL2H 5 +#define R8A73A4_CLK_Z 6 +#define R8A73A4_CLK_Z2 7 +#define R8A73A4_CLK_I 8 +#define R8A73A4_CLK_M3 9 +#define R8A73A4_CLK_B 10 +#define R8A73A4_CLK_M1 11 +#define R8A73A4_CLK_M2 12 +#define R8A73A4_CLK_ZX 13 +#define R8A73A4_CLK_ZS 14 +#define R8A73A4_CLK_HP 15 + +/* MSTP2 */ +#define R8A73A4_CLK_DMAC 18 +#define R8A73A4_CLK_SCIFB3 17 +#define R8A73A4_CLK_SCIFB2 16 +#define R8A73A4_CLK_SCIFB1 7 +#define R8A73A4_CLK_SCIFB0 6 +#define R8A73A4_CLK_SCIFA0 4 +#define R8A73A4_CLK_SCIFA1 3 + +/* MSTP3 */ +#define R8A73A4_CLK_CMT1 29 +#define R8A73A4_CLK_IIC1 23 +#define R8A73A4_CLK_IIC0 18 +#define R8A73A4_CLK_IIC7 17 +#define R8A73A4_CLK_IIC6 16 +#define R8A73A4_CLK_MMCIF0 15 +#define R8A73A4_CLK_SDHI0 14 +#define R8A73A4_CLK_SDHI1 13 +#define R8A73A4_CLK_SDHI2 12 +#define R8A73A4_CLK_MMCIF1 5 +#define R8A73A4_CLK_IIC2 0 + +/* MSTP4 */ +#define R8A73A4_CLK_IIC3 11 +#define R8A73A4_CLK_IIC4 10 +#define R8A73A4_CLK_IIC5 9 + +/* MSTP5 */ +#define R8A73A4_CLK_THERMAL 22 +#define R8A73A4_CLK_IIC8 15 + +#endif /* __DT_BINDINGS_CLOCK_R8A73A4_H__ */ -- cgit v1.2.3 From 83054671d28db9f1dbac1d3d1bf3b50b128e06ba Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Mon, 16 Feb 2015 17:58:46 +0100 Subject: ARM: shmobile: r8a7778: add CPG register bits header Enumerates CPG driver custom clocks and MSTP clock enable bits. Signed-off-by: Ulrich Hecht Acked-by: Laurent Pinchart Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- include/dt-bindings/clock/r8a7778-clock.h | 71 +++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 include/dt-bindings/clock/r8a7778-clock.h (limited to 'include') diff --git a/include/dt-bindings/clock/r8a7778-clock.h b/include/dt-bindings/clock/r8a7778-clock.h new file mode 100644 index 000000000000..f6b07c5399de --- /dev/null +++ b/include/dt-bindings/clock/r8a7778-clock.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 Ulrich Hecht + * + * 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 __DT_BINDINGS_CLOCK_R8A7778_H__ +#define __DT_BINDINGS_CLOCK_R8A7778_H__ + +/* CPG */ +#define R8A7778_CLK_PLLA 0 +#define R8A7778_CLK_PLLB 1 +#define R8A7778_CLK_B 2 +#define R8A7778_CLK_OUT 3 +#define R8A7778_CLK_P 4 +#define R8A7778_CLK_S 5 +#define R8A7778_CLK_S1 6 + +/* MSTP0 */ +#define R8A7778_CLK_I2C0 30 +#define R8A7778_CLK_I2C1 29 +#define R8A7778_CLK_I2C2 28 +#define R8A7778_CLK_I2C3 27 +#define R8A7778_CLK_SCIF0 26 +#define R8A7778_CLK_SCIF1 25 +#define R8A7778_CLK_SCIF2 24 +#define R8A7778_CLK_SCIF3 23 +#define R8A7778_CLK_SCIF4 22 +#define R8A7778_CLK_SCIF5 21 +#define R8A7778_CLK_TMU0 16 +#define R8A7778_CLK_TMU1 15 +#define R8A7778_CLK_TMU2 14 +#define R8A7778_CLK_SSI0 12 +#define R8A7778_CLK_SSI1 11 +#define R8A7778_CLK_SSI2 10 +#define R8A7778_CLK_SSI3 9 +#define R8A7778_CLK_SRU 8 +#define R8A7778_CLK_HSPI 7 + +/* MSTP1 */ +#define R8A7778_CLK_ETHER 14 +#define R8A7778_CLK_VIN0 10 +#define R8A7778_CLK_VIN1 9 +#define R8A7778_CLK_USB 0 + +/* MSTP3 */ +#define R8A7778_CLK_MMC 31 +#define R8A7778_CLK_SDHI0 23 +#define R8A7778_CLK_SDHI1 22 +#define R8A7778_CLK_SDHI2 21 +#define R8A7778_CLK_SSI4 11 +#define R8A7778_CLK_SSI5 10 +#define R8A7778_CLK_SSI6 9 +#define R8A7778_CLK_SSI7 8 +#define R8A7778_CLK_SSI8 7 + +/* MSTP5 */ +#define R8A7778_CLK_SRU_SRC0 31 +#define R8A7778_CLK_SRU_SRC1 30 +#define R8A7778_CLK_SRU_SRC2 29 +#define R8A7778_CLK_SRU_SRC3 28 +#define R8A7778_CLK_SRU_SRC4 27 +#define R8A7778_CLK_SRU_SRC5 26 +#define R8A7778_CLK_SRU_SRC6 25 +#define R8A7778_CLK_SRU_SRC7 24 +#define R8A7778_CLK_SRU_SRC8 23 + +#endif /* __DT_BINDINGS_CLOCK_R8A7778_H__ */ -- cgit v1.2.3 From 30ff54765976e132674e3eae2071ed8ed494665c Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Mon, 23 Feb 2015 08:17:12 -0500 Subject: net: sched: export tc_connmark.h so it is uapi accessible Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/uapi/linux/tc_act/Kbuild | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/linux/tc_act/Kbuild b/include/uapi/linux/tc_act/Kbuild index 19d5219b0b99..242cf0c6e33d 100644 --- a/include/uapi/linux/tc_act/Kbuild +++ b/include/uapi/linux/tc_act/Kbuild @@ -9,3 +9,4 @@ header-y += tc_pedit.h header-y += tc_skbedit.h header-y += tc_vlan.h header-y += tc_bpf.h +header-y += tc_connmark.h -- cgit v1.2.3 From 1af434a92871af93d97ce28e35497532a4167a0c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 22 Feb 2015 12:24:19 +0100 Subject: drm/atomic-helper: Rename commmit_post/pre_planes These names only make sense because of backwards compatability with the order used by the crtc helper library. There's not really any real requirement in the ordering here. So rename them to something more descriptive and update the kerneldoc a bit. Motivated in a discussion with Laurent about how to restore plane state for dpms for drivers with runtime pm. v2: Squash in fixup from Stephen Rothwell to fix a conflict with tegra. Cc: Laurent Pinchart Reviewed-by: Rob Clark Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 40 +++++++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_atomic.c | 4 ++-- drivers/gpu/drm/msm/msm_atomic.c | 4 ++-- drivers/gpu/drm/tegra/drm.c | 4 ++-- include/drm/drm_atomic_helper.h | 6 +++--- 5 files changed, 34 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 65b9adf5777c..9c528bbcd8d2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -768,34 +768,44 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) } /** - * drm_atomic_helper_commit_pre_planes - modeset commit before plane updates + * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs * @dev: DRM device * @old_state: atomic state object with old state structures * - * This function commits the modeset changes that need to be committed before - * updating planes. It shuts down all the outputs that need to be shut down and + * This function shuts down all the outputs that need to be shut down and * prepares them (if required) with the new mode. + * + * For compatability with legacy crtc helpers this should be called before + * drm_atomic_helper_commit_planes(), which is what the default commit function + * does. But drivers with different needs can group the modeset commits together + * and do the plane commits at the end. This is useful for drivers doing runtime + * PM since planes updates then only happen when the CRTC is actually enabled. */ -void drm_atomic_helper_commit_pre_planes(struct drm_device *dev, - struct drm_atomic_state *old_state) +void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, + struct drm_atomic_state *old_state) { disable_outputs(dev, old_state); set_routing_links(dev, old_state); crtc_set_mode(dev, old_state); } -EXPORT_SYMBOL(drm_atomic_helper_commit_pre_planes); +EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); /** - * drm_atomic_helper_commit_post_planes - modeset commit after plane updates + * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs * @dev: DRM device * @old_state: atomic state object with old state structures * - * This function commits the modeset changes that need to be committed after - * updating planes: It enables all the outputs with the new configuration which - * had to be turned off for the update. + * This function enables all the outputs with the new configuration which had to + * be turned off for the update. + * + * For compatability with legacy crtc helpers this should be called after + * drm_atomic_helper_commit_planes(), which is what the default commit function + * does. But drivers with different needs can group the modeset commits together + * and do the plane commits at the end. This is useful for drivers doing runtime + * PM since planes updates then only happen when the CRTC is actually enabled. */ -void drm_atomic_helper_commit_post_planes(struct drm_device *dev, - struct drm_atomic_state *old_state) +void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, + struct drm_atomic_state *old_state) { int ncrtcs = old_state->dev->mode_config.num_crtc; int i; @@ -861,7 +871,7 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, encoder->bridge->funcs->enable(encoder->bridge); } } -EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes); +EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); static void wait_for_fences(struct drm_device *dev, struct drm_atomic_state *state) @@ -1030,11 +1040,11 @@ int drm_atomic_helper_commit(struct drm_device *dev, wait_for_fences(dev, state); - drm_atomic_helper_commit_pre_planes(dev, state); + drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_planes(dev, state); - drm_atomic_helper_commit_post_planes(dev, state); + drm_atomic_helper_commit_modeset_enables(dev, state); drm_atomic_helper_wait_for_vblanks(dev, state); diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 19a9dd5408f3..011b8960fd75 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -134,9 +134,9 @@ int intel_atomic_commit(struct drm_device *dev, * FIXME: The proper sequence here will eventually be: * * drm_atomic_helper_swap_state(dev, state) - * drm_atomic_helper_commit_pre_planes(dev, state); + * drm_atomic_helper_commit_modeset_disables(dev, state); * drm_atomic_helper_commit_planes(dev, state); - * drm_atomic_helper_commit_post_planes(dev, state); + * drm_atomic_helper_commit_modeset_enables(dev, state); * drm_atomic_helper_wait_for_vblanks(dev, state); * drm_atomic_helper_cleanup_planes(dev, state); * drm_atomic_state_free(state); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 871aa2108dc6..7c412292a0ff 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -96,11 +96,11 @@ static void complete_commit(struct msm_commit *c) kms->funcs->prepare_commit(kms, state); - drm_atomic_helper_commit_pre_planes(dev, state); + drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_planes(dev, state); - drm_atomic_helper_commit_post_planes(dev, state); + drm_atomic_helper_commit_modeset_enables(dev, state); /* NOTE: _wait_for_vblanks() only waits for vblank on * enabled CRTCs. So we end up faulting when disabling diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 7dd328d77996..5f1880766110 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -55,9 +55,9 @@ static void tegra_atomic_complete(struct tegra_drm *tegra, * current layout. */ - drm_atomic_helper_commit_pre_planes(drm, state); + drm_atomic_helper_commit_modeset_disables(drm, state); drm_atomic_helper_commit_planes(drm, state); - drm_atomic_helper_commit_post_planes(drm, state); + drm_atomic_helper_commit_modeset_enables(drm, state); drm_atomic_helper_wait_for_vblanks(drm, state); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 8039d54a7441..829280b56874 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -43,9 +43,9 @@ int drm_atomic_helper_commit(struct drm_device *dev, void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state); -void drm_atomic_helper_commit_pre_planes(struct drm_device *dev, - struct drm_atomic_state *state); -void drm_atomic_helper_commit_post_planes(struct drm_device *dev, +void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, + struct drm_atomic_state *state); +void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *old_state); int drm_atomic_helper_prepare_planes(struct drm_device *dev, -- cgit v1.2.3 From c982bd90f58681d00363538167477e60e2c8f731 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 22 Feb 2015 12:24:20 +0100 Subject: drm/atomic-helpers: make mode_set hooks optional With runtime PM the hw might still be off while doing the ->mode_set callbacks - runtime PM get/put should only happen in the enable/disable hooks to properly support DPMS. Which essentially makes these callbacks useless for drivers support runtime PM, so make them optional. Again motivated by discussions with Laurent. Cc: Laurent Pinchart Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 5 +++-- include/drm/drm_crtc_helper.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 9c528bbcd8d2..28aa87510551 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -723,7 +723,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = crtc->helper_private; - if (crtc->state->enable) { + if (crtc->state->enable && funcs->mode_set_nofb) { DRM_DEBUG_ATOMIC("modeset on [CRTC:%d]\n", crtc->base.id); @@ -759,7 +759,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) * Each encoder has at most one connector (since we always steal * it away), so we won't call call mode_set hooks twice. */ - funcs->mode_set(encoder, mode, adjusted_mode); + if (funcs->mode_set) + funcs->mode_set(encoder, mode, adjusted_mode); if (encoder->bridge && encoder->bridge->funcs->mode_set) encoder->bridge->funcs->mode_set(encoder->bridge, diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index c250a22b39ab..92d5135b55d2 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -89,6 +89,7 @@ struct drm_crtc_helper_funcs { int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb); + /* Actually set the mode for atomic helpers, optional */ void (*mode_set_nofb)(struct drm_crtc *crtc); /* Move the crtc on the current fb to the given position *optional* */ @@ -119,7 +120,7 @@ struct drm_crtc_helper_funcs { * @mode_fixup: try to fixup proposed mode for this connector * @prepare: part of the disable sequence, called before the CRTC modeset * @commit: called after the CRTC modeset - * @mode_set: set this mode + * @mode_set: set this mode, optional for atomic helpers * @get_crtc: return CRTC that the encoder is currently attached to * @detect: connection status detection * @disable: disable encoder when not in use (overrides DPMS off) -- cgit v1.2.3 From e045d20bef41707dbba676e58624b54f9f39e172 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Thu, 19 Feb 2015 13:16:44 +0530 Subject: drm: Adding edp1.4 specific dpcd macros Adding dpcd macros related to edp1.4 and link rates v2: Added DP_SUPPORTED_LINK_RATES macros Signed-off-by: Sonika Jindal Reviewed-by: Todd Previte Signed-off-by: Daniel Vetter --- include/drm/drm_dp_helper.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 7e25030a6aa2..d4803224028f 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -92,6 +92,9 @@ # define DP_MSA_TIMING_PAR_IGNORED (1 << 6) /* eDP */ # define DP_OUI_SUPPORT (1 << 7) +#define DP_SUPPORTED_LINK_RATES 0x010 /*eDP 1.4*/ +#define DP_MAX_SUPPORTED_RATES 0x8 + #define DP_I2C_SPEED_CAP 0x00c /* DPI */ # define DP_I2C_SPEED_1K 0x01 # define DP_I2C_SPEED_5K 0x02 @@ -101,6 +104,7 @@ # define DP_I2C_SPEED_1M 0x20 #define DP_EDP_CONFIGURATION_CAP 0x00d /* XXX 1.2? */ +# define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ #define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ /* Multiple stream transport */ @@ -221,6 +225,8 @@ # define DP_UP_REQ_EN (1 << 1) # define DP_UPSTREAM_IS_SRC (1 << 2) +#define DP_LINK_RATE_SET 0x115 + #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ # define DP_PSR_ENABLE (1 << 0) # define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) @@ -332,6 +338,8 @@ # define DP_SET_POWER_D3 0x2 # define DP_SET_POWER_MASK 0x3 +#define DP_EDP_DPCD_REV 0x700 + #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ #define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400 /* 1.2 MST */ -- cgit v1.2.3 From 4d3199e4ca8e6670b54dc5ee070ffd54385988e9 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Sun, 22 Feb 2015 19:31:41 -0800 Subject: locking: Remove ACCESS_ONCE() usage With the new standardized functions, we can replace all ACCESS_ONCE() calls across relevant locking - this includes lockref and seqlock while at it. ACCESS_ONCE() does not work reliably on non-scalar types. For example gcc 4.6 and 4.7 might remove the volatile tag for such accesses during the SRA (scalar replacement of aggregates) step: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 Update the new calls regardless of if it is a scalar type, this is cleaner than having three alternatives. Signed-off-by: Davidlohr Bueso Cc: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Cc: Thomas Gleixner Cc: Paul E. McKenney Link: http://lkml.kernel.org/r/1424662301.6539.18.camel@stgolabs.net Signed-off-by: Ingo Molnar --- include/linux/seqlock.h | 6 +++--- kernel/locking/mcs_spinlock.h | 6 +++--- kernel/locking/mutex.c | 8 ++++---- kernel/locking/osq_lock.c | 14 +++++++------- kernel/locking/rwsem-xadd.c | 10 +++++----- lib/lockref.c | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index f5df8f687b4d..5f68d0a391ce 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h @@ -108,7 +108,7 @@ static inline unsigned __read_seqcount_begin(const seqcount_t *s) unsigned ret; repeat: - ret = ACCESS_ONCE(s->sequence); + ret = READ_ONCE(s->sequence); if (unlikely(ret & 1)) { cpu_relax(); goto repeat; @@ -127,7 +127,7 @@ repeat: */ static inline unsigned raw_read_seqcount(const seqcount_t *s) { - unsigned ret = ACCESS_ONCE(s->sequence); + unsigned ret = READ_ONCE(s->sequence); smp_rmb(); return ret; } @@ -179,7 +179,7 @@ static inline unsigned read_seqcount_begin(const seqcount_t *s) */ static inline unsigned raw_seqcount_begin(const seqcount_t *s) { - unsigned ret = ACCESS_ONCE(s->sequence); + unsigned ret = READ_ONCE(s->sequence); smp_rmb(); return ret & ~1; } diff --git a/kernel/locking/mcs_spinlock.h b/kernel/locking/mcs_spinlock.h index d1fe2ba5bac9..75e114bdf3f2 100644 --- a/kernel/locking/mcs_spinlock.h +++ b/kernel/locking/mcs_spinlock.h @@ -78,7 +78,7 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node) */ return; } - ACCESS_ONCE(prev->next) = node; + WRITE_ONCE(prev->next, node); /* Wait until the lock holder passes the lock down. */ arch_mcs_spin_lock_contended(&node->locked); @@ -91,7 +91,7 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node) static inline void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node) { - struct mcs_spinlock *next = ACCESS_ONCE(node->next); + struct mcs_spinlock *next = READ_ONCE(node->next); if (likely(!next)) { /* @@ -100,7 +100,7 @@ void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node) if (likely(cmpxchg(lock, node, NULL) == node)) return; /* Wait until the next pointer is set */ - while (!(next = ACCESS_ONCE(node->next))) + while (!(next = READ_ONCE(node->next))) cpu_relax_lowlatency(); } diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 43bf25ef3c81..16b2d3cc88b0 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -266,7 +266,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock) return 0; rcu_read_lock(); - owner = ACCESS_ONCE(lock->owner); + owner = READ_ONCE(lock->owner); if (owner) retval = owner->on_cpu; rcu_read_unlock(); @@ -340,7 +340,7 @@ static bool mutex_optimistic_spin(struct mutex *lock, * As such, when deadlock detection needs to be * performed the optimistic spinning cannot be done. */ - if (ACCESS_ONCE(ww->ctx)) + if (READ_ONCE(ww->ctx)) break; } @@ -348,7 +348,7 @@ static bool mutex_optimistic_spin(struct mutex *lock, * If there's an owner, wait for it to either * release the lock or go to sleep. */ - owner = ACCESS_ONCE(lock->owner); + owner = READ_ONCE(lock->owner); if (owner && !mutex_spin_on_owner(lock, owner)) break; @@ -487,7 +487,7 @@ static inline int __sched __ww_mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx) { struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); - struct ww_acquire_ctx *hold_ctx = ACCESS_ONCE(ww->ctx); + struct ww_acquire_ctx *hold_ctx = READ_ONCE(ww->ctx); if (!hold_ctx) return 0; diff --git a/kernel/locking/osq_lock.c b/kernel/locking/osq_lock.c index c112d00341b0..dc85ee23a26f 100644 --- a/kernel/locking/osq_lock.c +++ b/kernel/locking/osq_lock.c @@ -98,7 +98,7 @@ bool osq_lock(struct optimistic_spin_queue *lock) prev = decode_cpu(old); node->prev = prev; - ACCESS_ONCE(prev->next) = node; + WRITE_ONCE(prev->next, node); /* * Normally @prev is untouchable after the above store; because at that @@ -109,7 +109,7 @@ bool osq_lock(struct optimistic_spin_queue *lock) * cmpxchg in an attempt to undo our queueing. */ - while (!ACCESS_ONCE(node->locked)) { + while (!READ_ONCE(node->locked)) { /* * If we need to reschedule bail... so we can block. */ @@ -148,7 +148,7 @@ unqueue: * Or we race against a concurrent unqueue()'s step-B, in which * case its step-C will write us a new @node->prev pointer. */ - prev = ACCESS_ONCE(node->prev); + prev = READ_ONCE(node->prev); } /* @@ -170,8 +170,8 @@ unqueue: * it will wait in Step-A. */ - ACCESS_ONCE(next->prev) = prev; - ACCESS_ONCE(prev->next) = next; + WRITE_ONCE(next->prev, prev); + WRITE_ONCE(prev->next, next); return false; } @@ -193,11 +193,11 @@ void osq_unlock(struct optimistic_spin_queue *lock) node = this_cpu_ptr(&osq_node); next = xchg(&node->next, NULL); if (next) { - ACCESS_ONCE(next->locked) = 1; + WRITE_ONCE(next->locked, 1); return; } next = osq_wait_next(lock, node, NULL); if (next) - ACCESS_ONCE(next->locked) = 1; + WRITE_ONCE(next->locked, 1); } diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index e4ad019e23f5..06e2214edf98 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -279,7 +279,7 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem) */ static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem) { - long old, count = ACCESS_ONCE(sem->count); + long old, count = READ_ONCE(sem->count); while (true) { if (!(count == 0 || count == RWSEM_WAITING_BIAS)) @@ -304,9 +304,9 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem) return false; rcu_read_lock(); - owner = ACCESS_ONCE(sem->owner); + owner = READ_ONCE(sem->owner); if (!owner) { - long count = ACCESS_ONCE(sem->count); + long count = READ_ONCE(sem->count); /* * If sem->owner is not set, yet we have just recently entered the * slowpath with the lock being active, then there is a possibility @@ -385,7 +385,7 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem) goto done; while (true) { - owner = ACCESS_ONCE(sem->owner); + owner = READ_ONCE(sem->owner); if (owner && !rwsem_spin_on_owner(sem, owner)) break; @@ -459,7 +459,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem) /* we're now waiting on the lock, but no longer actively locking */ if (waiting) { - count = ACCESS_ONCE(sem->count); + count = READ_ONCE(sem->count); /* * If there were already threads queued before us and there are diff --git a/lib/lockref.c b/lib/lockref.c index ecb9a665ec19..494994bf17c8 100644 --- a/lib/lockref.c +++ b/lib/lockref.c @@ -18,7 +18,7 @@ #define CMPXCHG_LOOP(CODE, SUCCESS) do { \ struct lockref old; \ BUILD_BUG_ON(sizeof(old) != 8); \ - old.lock_count = ACCESS_ONCE(lockref->lock_count); \ + old.lock_count = READ_ONCE(lockref->lock_count); \ while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) { \ struct lockref new = old, prev = old; \ CODE \ -- cgit v1.2.3 From 5c9e719691eab8c5de8b1b68fc3da9f7c4470c38 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Feb 2015 17:10:03 +0100 Subject: regulator: core: Fix space before TAB Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- include/linux/regulator/consumer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index d17e1ff7ad01..aeacd624a794 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -114,7 +114,7 @@ struct regmap; #define REGULATOR_EVENT_OVER_TEMP 0x10 #define REGULATOR_EVENT_FORCE_DISABLE 0x20 #define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40 -#define REGULATOR_EVENT_DISABLE 0x80 +#define REGULATOR_EVENT_DISABLE 0x80 #define REGULATOR_EVENT_PRE_VOLTAGE_CHANGE 0x100 #define REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE 0x200 #define REGULATOR_EVENT_PRE_DISABLE 0x400 -- cgit v1.2.3 From f23e860edbb3f2208c0ab3448e756689bb4a3760 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sat, 14 Feb 2015 17:22:49 -0800 Subject: ASoC: core: Add extra dapm properties for Device Tree The current helper functions, snd_soc_of_parse_audio_simple_widgets() and snd_soc_of_parse_audio_routing(), set dapm_widgets and dapm_routes without caring if they are already set by using build-in widgets and routes in the card driver. So there could be one of them, build-in one or Device Tree one, overrided by the other depending on which one was assigned later. This patch adds an extra pair of dapm_widgets and dapm_routes for DT use only so as to prevent unexpected overriding. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..f66a1ef98a40 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1071,11 +1071,16 @@ struct snd_soc_card { /* * Card-specific routes and widgets. + * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in. */ const struct snd_soc_dapm_widget *dapm_widgets; int num_dapm_widgets; const struct snd_soc_dapm_route *dapm_routes; int num_dapm_routes; + const struct snd_soc_dapm_widget *of_dapm_widgets; + int num_of_dapm_widgets; + const struct snd_soc_dapm_route *of_dapm_routes; + int num_of_dapm_routes; bool fully_routed; struct work_struct deferred_resume_work; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 30579ca5bacb..5c0658d49609 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1561,6 +1561,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, card->num_dapm_widgets); + if (card->of_dapm_widgets) + snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, + card->num_of_dapm_widgets); + /* initialise the sound card only once */ if (card->probe) { ret = card->probe(card); @@ -1616,6 +1620,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, card->num_dapm_routes); + if (card->of_dapm_routes) + snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, + card->num_of_dapm_routes); + for (i = 0; i < card->num_links; i++) { if (card->dai_link[i].dai_fmt) snd_soc_runtime_set_dai_fmt(&card->rtd[i], @@ -3223,8 +3231,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, widgets[i].name = wname; } - card->dapm_widgets = widgets; - card->num_dapm_widgets = num_widgets; + card->of_dapm_widgets = widgets; + card->num_of_dapm_widgets = num_widgets; return 0; } @@ -3308,8 +3316,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } } - card->num_dapm_routes = num_routes; - card->dapm_routes = routes; + card->num_of_dapm_routes = num_routes; + card->of_dapm_routes = routes; return 0; } -- cgit v1.2.3 From 12ca7188468ee29c4e717f73db4bf43c90954fc7 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 13 Feb 2015 19:28:02 -0600 Subject: thermal: Introduce dummy functions when thermal is not defined When CONFIG_THERMAL is not enabled, it is better to introduce equivalent dummy functions in the exported header than to introduce #ifdeffery in drivers using the function. This will prevent issues such as that reported in: http://www.spinics.net/lists/linux-next/msg31573.html While at it switch over to IS_ENABLED for thermal macros to allow for thermal framework to be built as framework and relevant APIs be usable by relevant drivers as a result. Reported-by: Guenter Roeck Signed-off-by: Nishanth Menon Signed-off-by: Eduardo Valentin --- include/linux/thermal.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/thermal.h b/include/linux/thermal.h index fc52e307efab..5eac316490ea 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -314,6 +314,8 @@ void thermal_zone_of_sensor_unregister(struct device *dev, } #endif + +#if IS_ENABLED(CONFIG_THERMAL) struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, void *, struct thermal_zone_device_ops *, const struct thermal_zone_params *, int, int); @@ -340,8 +342,58 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *, struct thermal_cooling_device *, int); void thermal_cdev_update(struct thermal_cooling_device *); void thermal_notify_framework(struct thermal_zone_device *, int); - -#ifdef CONFIG_NET +#else +static inline struct thermal_zone_device *thermal_zone_device_register( + const char *type, int trips, int mask, void *devdata, + struct thermal_zone_device_ops *ops, + const struct thermal_zone_params *tzp, + int passive_delay, int polling_delay) +{ return ERR_PTR(-ENODEV); } +static inline void thermal_zone_device_unregister( + struct thermal_zone_device *tz) +{ } +static inline int thermal_zone_bind_cooling_device( + struct thermal_zone_device *tz, int trip, + struct thermal_cooling_device *cdev, + unsigned long upper, unsigned long lower) +{ return -ENODEV; } +static inline int thermal_zone_unbind_cooling_device( + struct thermal_zone_device *tz, int trip, + struct thermal_cooling_device *cdev) +{ return -ENODEV; } +static inline void thermal_zone_device_update(struct thermal_zone_device *tz) +{ } +static inline struct thermal_cooling_device * +thermal_cooling_device_register(char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) +{ return ERR_PTR(-ENODEV); } +static inline struct thermal_cooling_device * +thermal_of_cooling_device_register(struct device_node *np, + char *type, void *devdata, const struct thermal_cooling_device_ops *ops) +{ return ERR_PTR(-ENODEV); } +static inline void thermal_cooling_device_unregister( + struct thermal_cooling_device *cdev) +{ } +static inline struct thermal_zone_device *thermal_zone_get_zone_by_name( + const char *name) +{ return ERR_PTR(-ENODEV); } +static inline int thermal_zone_get_temp( + struct thermal_zone_device *tz, unsigned long *temp) +{ return -ENODEV; } +static inline int get_tz_trend(struct thermal_zone_device *tz, int trip) +{ return -ENODEV; } +static inline struct thermal_instance * +get_thermal_instance(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev, int trip) +{ return ERR_PTR(-ENODEV); } +static inline void thermal_cdev_update(struct thermal_cooling_device *cdev) +{ } +static inline void thermal_notify_framework(struct thermal_zone_device *tz, + int trip) +{ } +#endif /* CONFIG_THERMAL */ + +#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL) extern int thermal_generate_netlink_event(struct thermal_zone_device *tz, enum events event); #else -- cgit v1.2.3 From 0c571785813cf3294cdbb1f2fb1a9b19e11935f6 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Fri, 13 Feb 2015 08:06:47 -0800 Subject: leds: flash: remove stray include directive Avoid including v4l2-controls.h, as this is stray code from the early versions of the LED / V4L2 flash API integration patches. LED Flash class doesn't depend on V4L2 subsystem. Signed-off-by: Jacek Anaszewski Signed-off-by: Bryan Wu --- include/linux/led-class-flash.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/led-class-flash.h b/include/linux/led-class-flash.h index 5ba2facd7a51..3b5b9643cea1 100644 --- a/include/linux/led-class-flash.h +++ b/include/linux/led-class-flash.h @@ -13,7 +13,6 @@ #define __LINUX_FLASH_LEDS_H_INCLUDED #include -#include struct device_node; struct led_classdev_flash; -- cgit v1.2.3 From 14c9551a32eba086c9f20c9d6a8e378481f15333 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Mon, 23 Feb 2015 17:50:11 -0800 Subject: bonding: Implement port churn-machine (AD standard 43.4.17). The Churn Detection machines detect the situation where a port is operable, but the Actor and Partner have not attached the link to an Aggregator and brought the link into operation within a bound time period. Under normal operation of the LACP, agreement between Actor and Partner should be reached very rapidly. Continued failure to reach agreement can be symptomatic of device failure. Actor-churn-detection state-machine Reviewed-by: Nikolay Aleksandrov =================================== BEGIN=True + PortEnable=False | v +------------------------+ ActorPort.Sync=True +------------------+ | ACTOR_CHURN_MONITOR | ---------------------> | NO_ACTOR_CHURN | |========================| |==================| | ActorChurn=False | ActorPort.Sync=False | ActorChurn=False | | ActorChurn.Timer=Start | <--------------------- | | +------------------------+ +------------------+ | ^ | | ActorChurn.Timer=Expired | | ActorPort.Sync=True | | | +-----------------+ | | | ACTOR_CHURN | | | |=================| | +--------------> | ActorChurn=True | ------------+ | | +-----------------+ Similar for the Partner-churn-detection. Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 57 +++++++++++++++++++++++++++++++++++++-- drivers/net/bonding/bond_procfs.c | 43 +++++++++++++++++++++++++---- include/net/bond_3ad.h | 29 ++++++++++++++++++++ 3 files changed, 122 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 9b436696b95e..f61b2870cddf 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -38,6 +38,7 @@ #define AD_STANDBY 0x2 #define AD_MAX_TX_IN_SECOND 3 #define AD_COLLECTOR_MAX_DELAY 0 +#define AD_MONITOR_CHURNED 0x1000 /* Timer definitions (43.4.4 in the 802.3ad standard) */ #define AD_FAST_PERIODIC_TIME 1 @@ -1013,16 +1014,19 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) /* check if state machine should change state */ /* first, check if port was reinitialized */ - if (port->sm_vars & AD_PORT_BEGIN) + if (port->sm_vars & AD_PORT_BEGIN) { port->sm_rx_state = AD_RX_INITIALIZE; + port->sm_vars |= AD_MONITOR_CHURNED; /* check if port is not enabled */ - else if (!(port->sm_vars & AD_PORT_BEGIN) + } else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED)) port->sm_rx_state = AD_RX_PORT_DISABLED; /* check if new lacpdu arrived */ else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || (port->sm_rx_state == AD_RX_DEFAULTED) || (port->sm_rx_state == AD_RX_CURRENT))) { + if (port->sm_rx_state != AD_RX_CURRENT) + port->sm_vars |= AD_MONITOR_CHURNED; port->sm_rx_timer_counter = 0; port->sm_rx_state = AD_RX_CURRENT; } else { @@ -1100,9 +1104,11 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) */ port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; + port->partner_oper.port_state |= AD_STATE_LACP_TIMEOUT; port->partner_oper.port_state |= AD_STATE_LACP_ACTIVITY; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= AD_STATE_EXPIRED; + port->sm_vars |= AD_MONITOR_CHURNED; break; case AD_RX_DEFAULTED: __update_default_selected(port); @@ -1131,6 +1137,45 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) } } +/** + * ad_churn_machine - handle port churn's state machine + * @port: the port we're looking at + * + */ +static void ad_churn_machine(struct port *port) +{ + if (port->sm_vars & AD_MONITOR_CHURNED) { + port->sm_vars &= ~AD_MONITOR_CHURNED; + port->sm_churn_actor_state = AD_CHURN_MONITOR; + port->sm_churn_partner_state = AD_CHURN_MONITOR; + port->sm_churn_actor_timer_counter = + __ad_timer_to_ticks(AD_ACTOR_CHURN_TIMER, 0); + port->sm_churn_partner_timer_counter = + __ad_timer_to_ticks(AD_PARTNER_CHURN_TIMER, 0); + return; + } + if (port->sm_churn_actor_timer_counter && + !(--port->sm_churn_actor_timer_counter) && + port->sm_churn_actor_state == AD_CHURN_MONITOR) { + if (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION) { + port->sm_churn_actor_state = AD_NO_CHURN; + } else { + port->churn_actor_count++; + port->sm_churn_actor_state = AD_CHURN; + } + } + if (port->sm_churn_partner_timer_counter && + !(--port->sm_churn_partner_timer_counter) && + port->sm_churn_partner_state == AD_CHURN_MONITOR) { + if (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) { + port->sm_churn_partner_state = AD_NO_CHURN; + } else { + port->churn_partner_count++; + port->sm_churn_partner_state = AD_CHURN; + } + } +} + /** * ad_tx_machine - handle a port's tx state machine * @port: the port we're looking at @@ -1745,6 +1790,13 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->next_port_in_aggregator = NULL; port->transaction_id = 0; + port->sm_churn_actor_timer_counter = 0; + port->sm_churn_actor_state = 0; + port->churn_actor_count = 0; + port->sm_churn_partner_timer_counter = 0; + port->sm_churn_partner_state = 0; + port->churn_partner_count = 0; + memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu)); } } @@ -2164,6 +2216,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work) ad_port_selection_logic(port, &update_slave_arr); ad_mux_machine(port, &update_slave_arr); ad_tx_machine(port); + ad_churn_machine(port); /* turn off the BEGIN bit, since we already handled it */ if (port->sm_vars & AD_PORT_BEGIN) diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 976f5ad2a0f2..62694cfc05b6 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -176,18 +176,51 @@ static void bond_info_show_slave(struct seq_file *seq, slave->link_failure_count); seq_printf(seq, "Permanent HW addr: %pM\n", slave->perm_hwaddr); + seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id); if (BOND_MODE(bond) == BOND_MODE_8023AD) { - const struct aggregator *agg - = SLAVE_AD_INFO(slave)->port.aggregator; + const struct port *port = &SLAVE_AD_INFO(slave)->port; + const struct aggregator *agg = port->aggregator; - if (agg) + if (agg) { seq_printf(seq, "Aggregator ID: %d\n", agg->aggregator_identifier); - else + seq_printf(seq, "Actor Churn State: %s\n", + bond_3ad_churn_desc(port->sm_churn_actor_state)); + seq_printf(seq, "Partner Churn State: %s\n", + bond_3ad_churn_desc(port->sm_churn_partner_state)); + seq_printf(seq, "Actor Churned Count: %d\n", + port->churn_actor_count); + seq_printf(seq, "Partner Churned Count: %d\n", + port->churn_partner_count); + + seq_puts(seq, "details actor lacp pdu:\n"); + seq_printf(seq, " system priority: %d\n", + port->actor_system_priority); + seq_printf(seq, " port key: %d\n", + port->actor_oper_port_key); + seq_printf(seq, " port priority: %d\n", + port->actor_port_priority); + seq_printf(seq, " port number: %d\n", + port->actor_port_number); + seq_printf(seq, " port state: %d\n", + port->actor_oper_port_state); + + seq_puts(seq, "details partner lacp pdu:\n"); + seq_printf(seq, " system priority: %d\n", + port->partner_oper.system_priority); + seq_printf(seq, " oper key: %d\n", + port->partner_oper.key); + seq_printf(seq, " port priority: %d\n", + port->partner_oper.port_priority); + seq_printf(seq, " port number: %d\n", + port->partner_oper.port_number); + seq_printf(seq, " port state: %d\n", + port->partner_oper.port_state); + } else { seq_puts(seq, "Aggregator ID: N/A\n"); + } } - seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id); } static int bond_info_seq_show(struct seq_file *seq, void *v) diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h index f04cdbb7848e..c2a40a172fcd 100644 --- a/include/net/bond_3ad.h +++ b/include/net/bond_3ad.h @@ -82,6 +82,13 @@ typedef enum { AD_TRANSMIT /* tx Machine */ } tx_states_t; +/* churn machine states(43.4.17 in the 802.3ad standard) */ +typedef enum { + AD_CHURN_MONITOR, /* monitoring for churn */ + AD_CHURN, /* churn detected (error) */ + AD_NO_CHURN /* no churn (no error) */ +} churn_state_t; + /* rx indication types */ typedef enum { AD_TYPE_LACPDU = 1, /* type lacpdu */ @@ -229,6 +236,12 @@ typedef struct port { u16 sm_mux_timer_counter; /* state machine mux timer counter */ tx_states_t sm_tx_state; /* state machine tx state */ u16 sm_tx_timer_counter; /* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */ + u16 sm_churn_actor_timer_counter; + u16 sm_churn_partner_timer_counter; + u32 churn_actor_count; + u32 churn_partner_count; + churn_state_t sm_churn_actor_state; + churn_state_t sm_churn_partner_state; struct slave *slave; /* pointer to the bond slave that this port belongs to */ struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ @@ -262,6 +275,22 @@ struct ad_slave_info { u16 id; }; +static inline const char *bond_3ad_churn_desc(churn_state_t state) +{ + static const char *const churn_description[] = { + "monitoring", + "churned", + "none", + "unknown" + }; + int max_size = sizeof(churn_description) / sizeof(churn_description[0]); + + if (state >= max_size) + state = max_size - 1; + + return churn_description[state]; +} + /* ========== AD Exported functions to the main bonding code ========== */ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution); void bond_3ad_bind_slave(struct slave *slave); -- cgit v1.2.3 From d752c364571743d696c2a54a449ce77550c35ac5 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Mon, 23 Feb 2015 15:02:34 -0300 Subject: ipvs: allow rescheduling of new connections when port reuse is detected Currently, when TCP/SCTP port reusing happens, IPVS will find the old entry and use it for the new one, behaving like a forced persistence. But if you consider a cluster with a heavy load of small connections, such reuse will happen often and may lead to a not optimal load balancing and might prevent a new node from getting a fair load. This patch introduces a new sysctl, conn_reuse_mode, that allows controlling how to proceed when port reuse is detected. The default value will allow rescheduling of new connections only if the old entry was in TIME_WAIT state for TCP or CLOSED for SCTP. Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman --- Documentation/networking/ipvs-sysctl.txt | 21 ++++++++++++++++++++ include/net/ip_vs.h | 11 +++++++++++ net/netfilter/ipvs/ip_vs_core.c | 33 ++++++++++++++++++++++++++++---- net/netfilter/ipvs/ip_vs_ctl.c | 8 ++++++++ net/netfilter/ipvs/ip_vs_sync.c | 21 ++++++++++++++++++-- 5 files changed, 88 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index 7a3c04729591..3ba709531adb 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -22,6 +22,27 @@ backup_only - BOOLEAN If set, disable the director function while the server is in backup mode to avoid packet loops for DR/TUN methods. +conn_reuse_mode - INTEGER + 1 - default + + Controls how ipvs will deal with connections that are detected + port reuse. It is a bitmap, with the values being: + + 0: disable any special handling on port reuse. The new + connection will be delivered to the same real server that was + servicing the previous connection. This will effectively + disable expire_nodest_conn. + + bit 1: enable rescheduling of new connections when it is safe. + That is, whenever expire_nodest_conn and for TCP sockets, when + the connection is in TIME_WAIT state (which is only possible if + you use NAT mode). + + bit 2: it is bit 1 plus, for TCP connections, when connections + are in FIN_WAIT state, as this is the last state seen by load + balancer in Direct Routing mode. This bit helps on adding new + real servers to a very busy cluster. + conntrack - BOOLEAN 0 - disabled (default) not 0 - enabled diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index a627fe690c19..20fd23398537 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -941,6 +941,7 @@ struct netns_ipvs { int sysctl_nat_icmp_send; int sysctl_pmtu_disc; int sysctl_backup_only; + int sysctl_conn_reuse_mode; /* ip_vs_lblc */ int sysctl_lblc_expiration; @@ -1059,6 +1060,11 @@ static inline int sysctl_backup_only(struct netns_ipvs *ipvs) ipvs->sysctl_backup_only; } +static inline int sysctl_conn_reuse_mode(struct netns_ipvs *ipvs) +{ + return ipvs->sysctl_conn_reuse_mode; +} + #else static inline int sysctl_sync_threshold(struct netns_ipvs *ipvs) @@ -1126,6 +1132,11 @@ static inline int sysctl_backup_only(struct netns_ipvs *ipvs) return 0; } +static inline int sysctl_conn_reuse_mode(struct netns_ipvs *ipvs) +{ + return 1; +} + #endif /* IPVS core functions diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index c9470c86308f..6103ab933c5b 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1042,6 +1042,26 @@ static inline bool is_new_conn(const struct sk_buff *skb, } } +static inline bool is_new_conn_expected(const struct ip_vs_conn *cp, + int conn_reuse_mode) +{ + /* Controlled (FTP DATA or persistence)? */ + if (cp->control) + return false; + + switch (cp->protocol) { + case IPPROTO_TCP: + return (cp->state == IP_VS_TCP_S_TIME_WAIT) || + ((conn_reuse_mode & 2) && + (cp->state == IP_VS_TCP_S_FIN_WAIT) && + (cp->flags & IP_VS_CONN_F_NOOUTPUT)); + case IPPROTO_SCTP: + return cp->state == IP_VS_SCTP_S_CLOSED; + default: + return false; + } +} + /* Handle response packets: rewrite addresses and send away... */ static unsigned int @@ -1580,6 +1600,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) struct ip_vs_conn *cp; int ret, pkts; struct netns_ipvs *ipvs; + int conn_reuse_mode; /* Already marked as IPVS request or reply? */ if (skb->ipvs_property) @@ -1648,10 +1669,14 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) */ cp = pp->conn_in_get(af, skb, &iph, 0); - if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp && cp->dest && - unlikely(!atomic_read(&cp->dest->weight)) && !iph.fragoffs && - is_new_conn(skb, &iph)) { - ip_vs_conn_expire_now(cp); + conn_reuse_mode = sysctl_conn_reuse_mode(ipvs); + if (conn_reuse_mode && !iph.fragoffs && + is_new_conn(skb, &iph) && cp && + ((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest && + unlikely(!atomic_read(&cp->dest->weight))) || + unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) { + if (!atomic_read(&cp->n_control)) + ip_vs_conn_expire_now(cp); __ip_vs_conn_put(cp); cp = NULL; } diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 6fd60059faf0..76cc9ffd87fa 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1823,6 +1823,12 @@ static struct ctl_table vs_vars[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "conn_reuse_mode", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, #ifdef CONFIG_IP_VS_DEBUG { .procname = "debug_level", @@ -3790,6 +3796,8 @@ static int __net_init ip_vs_control_net_init_sysctl(struct net *net) ipvs->sysctl_pmtu_disc = 1; tbl[idx++].data = &ipvs->sysctl_pmtu_disc; tbl[idx++].data = &ipvs->sysctl_backup_only; + ipvs->sysctl_conn_reuse_mode = 1; + tbl[idx++].data = &ipvs->sysctl_conn_reuse_mode; ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl); diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index c47ffd7a0a70..f96229cdb6e1 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -845,10 +845,27 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, struct ip_vs_conn *cp; struct netns_ipvs *ipvs = net_ipvs(net); - if (!(flags & IP_VS_CONN_F_TEMPLATE)) + if (!(flags & IP_VS_CONN_F_TEMPLATE)) { cp = ip_vs_conn_in_get(param); - else + if (cp && ((cp->dport != dport) || + !ip_vs_addr_equal(cp->daf, &cp->daddr, daddr))) { + if (!(flags & IP_VS_CONN_F_INACTIVE)) { + ip_vs_conn_expire_now(cp); + __ip_vs_conn_put(cp); + cp = NULL; + } else { + /* This is the expiration message for the + * connection that was already replaced, so we + * just ignore it. + */ + __ip_vs_conn_put(cp); + kfree(param->pe_data); + return; + } + } + } else { cp = ip_vs_ct_in_get(param); + } if (cp) { /* Free pe_data */ -- cgit v1.2.3 From 39bed6cbb842d8edf5a26b01122b391d36775b5e Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 23 Jan 2015 18:45:40 +0000 Subject: perf: Make perf_cgroup_from_task() global Move perf_cgroup_from_task() from kernel/events/ to include/linux/ along with the necessary struct definitions, so that it can be used by the PMU code. When the upcoming Intel Cache Monitoring PMU driver assigns monitoring IDs to perf events, it needs to be able to check whether any two monitoring events overlap (say, a cgroup and task event), which means we need to be able to lookup the cgroup associated with a task (if any). Signed-off-by: Matt Fleming Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kanaka Juvva Cc: Linus Torvalds Cc: Paul Mackerras Cc: Vikas Shivappa Link: http://lkml.kernel.org/r/1422038748-21397-2-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 30 ++++++++++++++++++++++++++++++ kernel/events/core.c | 28 +--------------------------- 2 files changed, 31 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 724d3720c9b1..cae4a9481777 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -53,6 +53,7 @@ struct perf_guest_info_callbacks { #include #include #include +#include #include struct perf_callchain_entry { @@ -547,6 +548,35 @@ struct perf_output_handle { int page; }; +#ifdef CONFIG_CGROUP_PERF + +/* + * perf_cgroup_info keeps track of time_enabled for a cgroup. + * This is a per-cpu dynamically allocated data structure. + */ +struct perf_cgroup_info { + u64 time; + u64 timestamp; +}; + +struct perf_cgroup { + struct cgroup_subsys_state css; + struct perf_cgroup_info __percpu *info; +}; + +/* + * Must ensure cgroup is pinned (css_get) before calling + * this function. In other words, we cannot call this function + * if there is no cgroup event for the current CPU context. + */ +static inline struct perf_cgroup * +perf_cgroup_from_task(struct task_struct *task) +{ + return container_of(task_css(task, perf_event_cgrp_id), + struct perf_cgroup, css); +} +#endif /* CONFIG_CGROUP_PERF */ + #ifdef CONFIG_PERF_EVENTS extern int perf_pmu_register(struct pmu *pmu, const char *name, int type); diff --git a/kernel/events/core.c b/kernel/events/core.c index 20cece0a7aea..072de3143244 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -34,11 +34,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -351,32 +351,6 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx, #ifdef CONFIG_CGROUP_PERF -/* - * perf_cgroup_info keeps track of time_enabled for a cgroup. - * This is a per-cpu dynamically allocated data structure. - */ -struct perf_cgroup_info { - u64 time; - u64 timestamp; -}; - -struct perf_cgroup { - struct cgroup_subsys_state css; - struct perf_cgroup_info __percpu *info; -}; - -/* - * Must ensure cgroup is pinned (css_get) before calling - * this function. In other words, we cannot call this function - * if there is no cgroup event for the current CPU context. - */ -static inline struct perf_cgroup * -perf_cgroup_from_task(struct task_struct *task) -{ - return container_of(task_css(task, perf_event_cgrp_id), - struct perf_cgroup, css); -} - static inline bool perf_cgroup_match(struct perf_event *event) { -- cgit v1.2.3 From eacd3ecc34472ce3751eedfc94e44c7cc6eb6305 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 23 Jan 2015 18:45:41 +0000 Subject: perf: Add ->count() function to read per-package counters For PMU drivers that record per-package counters, the ->count variable cannot be used to record an accurate aggregated value, since it's not possible to perform SMP cross-calls to cpus on other packages from the context in which we update ->count. Introduce a new optional ->count() accessor function that can be used to customize how values are collected. If a PMU driver doesn't provide a ->count() function, we fallback to the existing code. There is necessarily a window of staleness with this approach because the task that generated the counter value may not have been scheduled by the cpu recently. An alternative and more complex approach would be to use a hrtimer to periodically refresh the values from a more permissive scheduling context. So, we're trading off complexity for accuracy. Signed-off-by: Matt Fleming Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kanaka Juvva Cc: Linus Torvalds Cc: Vikas Shivappa Link: http://lkml.kernel.org/r/1422038748-21397-3-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 10 ++++++++++ kernel/events/core.c | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index cae4a9481777..9fc9b0d31442 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -272,6 +272,11 @@ struct pmu { */ size_t task_ctx_size; + + /* + * Return the count value for a counter. + */ + u64 (*count) (struct perf_event *event); /*optional*/ }; /** @@ -770,6 +775,11 @@ static inline void perf_event_task_sched_out(struct task_struct *prev, __perf_event_task_sched_out(prev, next); } +static inline u64 __perf_event_count(struct perf_event *event) +{ + return local64_read(&event->count) + atomic64_read(&event->child_count); +} + extern void perf_event_mmap(struct vm_area_struct *vma); extern struct perf_guest_info_callbacks *perf_guest_cbs; extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); diff --git a/kernel/events/core.c b/kernel/events/core.c index 072de3143244..4e8dc596f101 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3194,7 +3194,10 @@ static void __perf_event_read(void *info) static inline u64 perf_event_count(struct perf_event *event) { - return local64_read(&event->count) + atomic64_read(&event->child_count); + if (event->pmu->count) + return event->pmu->count(event); + + return __perf_event_count(event); } static u64 perf_event_read(struct perf_event *event) -- cgit v1.2.3 From 4afbb24ce5e723c8a093a6674a3c33062175078a Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 23 Jan 2015 18:45:44 +0000 Subject: perf/x86/intel: Add Intel Cache QoS Monitoring support Future Intel Xeon processors support a Cache QoS Monitoring feature that allows tracking of the LLC occupancy for a task or task group, i.e. the amount of data in pulled into the LLC for the task (group). Currently the PMU only supports per-cpu events. We create an event for each cpu and read out all the LLC occupancy values. Because this results in duplicate values being written out to userspace, we also export a .per-pkg event file so that the perf tools only accumulate values for one cpu per package. Signed-off-by: Matt Fleming Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kanaka Juvva Cc: Linus Torvalds Cc: Vikas Shivappa Link: http://lkml.kernel.org/r/1422038748-21397-6-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_cqm.c | 530 +++++++++++++++++++++++++++++ include/linux/perf_event.h | 7 + 2 files changed, 537 insertions(+) create mode 100644 arch/x86/kernel/cpu/perf_event_intel_cqm.c (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c new file mode 100644 index 000000000000..05b4cd26f426 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c @@ -0,0 +1,530 @@ +/* + * Intel Cache Quality-of-Service Monitoring (CQM) support. + * + * Based very, very heavily on work by Peter Zijlstra. + */ + +#include +#include +#include +#include "perf_event.h" + +#define MSR_IA32_PQR_ASSOC 0x0c8f +#define MSR_IA32_QM_CTR 0x0c8e +#define MSR_IA32_QM_EVTSEL 0x0c8d + +static unsigned int cqm_max_rmid = -1; +static unsigned int cqm_l3_scale; /* supposedly cacheline size */ + +struct intel_cqm_state { + raw_spinlock_t lock; + int rmid; + int cnt; +}; + +static DEFINE_PER_CPU(struct intel_cqm_state, cqm_state); + +/* + * Protects cache_cgroups. + */ +static DEFINE_MUTEX(cache_mutex); + +/* + * Groups of events that have the same target(s), one RMID per group. + */ +static LIST_HEAD(cache_groups); + +/* + * Mask of CPUs for reading CQM values. We only need one per-socket. + */ +static cpumask_t cqm_cpumask; + +#define RMID_VAL_ERROR (1ULL << 63) +#define RMID_VAL_UNAVAIL (1ULL << 62) + +#define QOS_L3_OCCUP_EVENT_ID (1 << 0) + +#define QOS_EVENT_MASK QOS_L3_OCCUP_EVENT_ID + +static u64 __rmid_read(unsigned long rmid) +{ + u64 val; + + /* + * Ignore the SDM, this thing is _NOTHING_ like a regular perfcnt, + * it just says that to increase confusion. + */ + wrmsr(MSR_IA32_QM_EVTSEL, QOS_L3_OCCUP_EVENT_ID, rmid); + rdmsrl(MSR_IA32_QM_CTR, val); + + /* + * Aside from the ERROR and UNAVAIL bits, assume this thing returns + * the number of cachelines tagged with @rmid. + */ + return val; +} + +static unsigned long *cqm_rmid_bitmap; + +/* + * Returns < 0 on fail. + */ +static int __get_rmid(void) +{ + return bitmap_find_free_region(cqm_rmid_bitmap, cqm_max_rmid, 0); +} + +static void __put_rmid(int rmid) +{ + bitmap_release_region(cqm_rmid_bitmap, rmid, 0); +} + +static int intel_cqm_setup_rmid_cache(void) +{ + cqm_rmid_bitmap = kmalloc(sizeof(long) * BITS_TO_LONGS(cqm_max_rmid), GFP_KERNEL); + if (!cqm_rmid_bitmap) + return -ENOMEM; + + bitmap_zero(cqm_rmid_bitmap, cqm_max_rmid); + + /* + * RMID 0 is special and is always allocated. It's used for all + * tasks that are not monitored. + */ + bitmap_allocate_region(cqm_rmid_bitmap, 0, 0); + + return 0; +} + +/* + * Determine if @a and @b measure the same set of tasks. + */ +static bool __match_event(struct perf_event *a, struct perf_event *b) +{ + if ((a->attach_state & PERF_ATTACH_TASK) != + (b->attach_state & PERF_ATTACH_TASK)) + return false; + + /* not task */ + + return true; /* if not task, we're machine wide */ +} + +/* + * Determine if @a's tasks intersect with @b's tasks + */ +static bool __conflict_event(struct perf_event *a, struct perf_event *b) +{ + /* + * If one of them is not a task, same story as above with cgroups. + */ + if (!(a->attach_state & PERF_ATTACH_TASK) || + !(b->attach_state & PERF_ATTACH_TASK)) + return true; + + /* + * Must be non-overlapping. + */ + return false; +} + +/* + * Find a group and setup RMID. + * + * If we're part of a group, we use the group's RMID. + */ +static int intel_cqm_setup_event(struct perf_event *event, + struct perf_event **group) +{ + struct perf_event *iter; + int rmid; + + list_for_each_entry(iter, &cache_groups, hw.cqm_groups_entry) { + if (__match_event(iter, event)) { + /* All tasks in a group share an RMID */ + event->hw.cqm_rmid = iter->hw.cqm_rmid; + *group = iter; + return 0; + } + + if (__conflict_event(iter, event)) + return -EBUSY; + } + + rmid = __get_rmid(); + if (rmid < 0) + return rmid; + + event->hw.cqm_rmid = rmid; + return 0; +} + +static void intel_cqm_event_read(struct perf_event *event) +{ + unsigned long rmid = event->hw.cqm_rmid; + u64 val; + + val = __rmid_read(rmid); + + /* + * Ignore this reading on error states and do not update the value. + */ + if (val & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL)) + return; + + local64_set(&event->count, val); +} + +static void intel_cqm_event_start(struct perf_event *event, int mode) +{ + struct intel_cqm_state *state = this_cpu_ptr(&cqm_state); + unsigned long rmid = event->hw.cqm_rmid; + unsigned long flags; + + if (!(event->hw.cqm_state & PERF_HES_STOPPED)) + return; + + event->hw.cqm_state &= ~PERF_HES_STOPPED; + + raw_spin_lock_irqsave(&state->lock, flags); + + if (state->cnt++) + WARN_ON_ONCE(state->rmid != rmid); + else + WARN_ON_ONCE(state->rmid); + + state->rmid = rmid; + wrmsrl(MSR_IA32_PQR_ASSOC, state->rmid); + + raw_spin_unlock_irqrestore(&state->lock, flags); +} + +static void intel_cqm_event_stop(struct perf_event *event, int mode) +{ + struct intel_cqm_state *state = this_cpu_ptr(&cqm_state); + unsigned long flags; + + if (event->hw.cqm_state & PERF_HES_STOPPED) + return; + + event->hw.cqm_state |= PERF_HES_STOPPED; + + raw_spin_lock_irqsave(&state->lock, flags); + intel_cqm_event_read(event); + + if (!--state->cnt) { + state->rmid = 0; + wrmsrl(MSR_IA32_PQR_ASSOC, 0); + } else { + WARN_ON_ONCE(!state->rmid); + } + + raw_spin_unlock_irqrestore(&state->lock, flags); +} + +static int intel_cqm_event_add(struct perf_event *event, int mode) +{ + int rmid; + + event->hw.cqm_state = PERF_HES_STOPPED; + rmid = event->hw.cqm_rmid; + WARN_ON_ONCE(!rmid); + + if (mode & PERF_EF_START) + intel_cqm_event_start(event, mode); + + return 0; +} + +static void intel_cqm_event_del(struct perf_event *event, int mode) +{ + intel_cqm_event_stop(event, mode); +} + +static void intel_cqm_event_destroy(struct perf_event *event) +{ + struct perf_event *group_other = NULL; + + mutex_lock(&cache_mutex); + + /* + * If there's another event in this group... + */ + if (!list_empty(&event->hw.cqm_group_entry)) { + group_other = list_first_entry(&event->hw.cqm_group_entry, + struct perf_event, + hw.cqm_group_entry); + list_del(&event->hw.cqm_group_entry); + } + + /* + * And we're the group leader.. + */ + if (!list_empty(&event->hw.cqm_groups_entry)) { + /* + * If there was a group_other, make that leader, otherwise + * destroy the group and return the RMID. + */ + if (group_other) { + list_replace(&event->hw.cqm_groups_entry, + &group_other->hw.cqm_groups_entry); + } else { + int rmid = event->hw.cqm_rmid; + + __put_rmid(rmid); + list_del(&event->hw.cqm_groups_entry); + } + } + + mutex_unlock(&cache_mutex); +} + +static struct pmu intel_cqm_pmu; + +/* + * XXX there's a bit of a problem in that we cannot simply do the one + * event per node as one would want, since that one event would one get + * scheduled on the one cpu. But we want to 'schedule' the RMID on all + * CPUs. + * + * This means we want events for each CPU, however, that generates a lot + * of duplicate values out to userspace -- this is not to be helped + * unless we want to change the core code in some way. Fore more info, + * see intel_cqm_event_read(). + */ +static int intel_cqm_event_init(struct perf_event *event) +{ + struct perf_event *group = NULL; + int err; + + if (event->attr.type != intel_cqm_pmu.type) + return -ENOENT; + + if (event->attr.config & ~QOS_EVENT_MASK) + return -EINVAL; + + if (event->cpu == -1) + return -EINVAL; + + /* unsupported modes and filters */ + if (event->attr.exclude_user || + event->attr.exclude_kernel || + event->attr.exclude_hv || + event->attr.exclude_idle || + event->attr.exclude_host || + event->attr.exclude_guest || + event->attr.sample_period) /* no sampling */ + return -EINVAL; + + INIT_LIST_HEAD(&event->hw.cqm_group_entry); + INIT_LIST_HEAD(&event->hw.cqm_groups_entry); + + event->destroy = intel_cqm_event_destroy; + + mutex_lock(&cache_mutex); + + err = intel_cqm_setup_event(event, &group); /* will also set rmid */ + if (err) + goto out; + + if (group) { + list_add_tail(&event->hw.cqm_group_entry, + &group->hw.cqm_group_entry); + } else { + list_add_tail(&event->hw.cqm_groups_entry, + &cache_groups); + } + +out: + mutex_unlock(&cache_mutex); + return err; +} + +EVENT_ATTR_STR(llc_occupancy, intel_cqm_llc, "event=0x01"); +EVENT_ATTR_STR(llc_occupancy.per-pkg, intel_cqm_llc_pkg, "1"); +EVENT_ATTR_STR(llc_occupancy.unit, intel_cqm_llc_unit, "Bytes"); +EVENT_ATTR_STR(llc_occupancy.scale, intel_cqm_llc_scale, NULL); +EVENT_ATTR_STR(llc_occupancy.snapshot, intel_cqm_llc_snapshot, "1"); + +static struct attribute *intel_cqm_events_attr[] = { + EVENT_PTR(intel_cqm_llc), + EVENT_PTR(intel_cqm_llc_pkg), + EVENT_PTR(intel_cqm_llc_unit), + EVENT_PTR(intel_cqm_llc_scale), + EVENT_PTR(intel_cqm_llc_snapshot), + NULL, +}; + +static struct attribute_group intel_cqm_events_group = { + .name = "events", + .attrs = intel_cqm_events_attr, +}; + +PMU_FORMAT_ATTR(event, "config:0-7"); +static struct attribute *intel_cqm_formats_attr[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group intel_cqm_format_group = { + .name = "format", + .attrs = intel_cqm_formats_attr, +}; + +static const struct attribute_group *intel_cqm_attr_groups[] = { + &intel_cqm_events_group, + &intel_cqm_format_group, + NULL, +}; + +static struct pmu intel_cqm_pmu = { + .attr_groups = intel_cqm_attr_groups, + .task_ctx_nr = perf_sw_context, + .event_init = intel_cqm_event_init, + .add = intel_cqm_event_add, + .del = intel_cqm_event_del, + .start = intel_cqm_event_start, + .stop = intel_cqm_event_stop, + .read = intel_cqm_event_read, +}; + +static inline void cqm_pick_event_reader(int cpu) +{ + int phys_id = topology_physical_package_id(cpu); + int i; + + for_each_cpu(i, &cqm_cpumask) { + if (phys_id == topology_physical_package_id(i)) + return; /* already got reader for this socket */ + } + + cpumask_set_cpu(cpu, &cqm_cpumask); +} + +static void intel_cqm_cpu_prepare(unsigned int cpu) +{ + struct intel_cqm_state *state = &per_cpu(cqm_state, cpu); + struct cpuinfo_x86 *c = &cpu_data(cpu); + + raw_spin_lock_init(&state->lock); + state->rmid = 0; + state->cnt = 0; + + WARN_ON(c->x86_cache_max_rmid != cqm_max_rmid); + WARN_ON(c->x86_cache_occ_scale != cqm_l3_scale); +} + +static void intel_cqm_cpu_exit(unsigned int cpu) +{ + int phys_id = topology_physical_package_id(cpu); + int i; + + /* + * Is @cpu a designated cqm reader? + */ + if (!cpumask_test_and_clear_cpu(cpu, &cqm_cpumask)) + return; + + for_each_online_cpu(i) { + if (i == cpu) + continue; + + if (phys_id == topology_physical_package_id(i)) { + cpumask_set_cpu(i, &cqm_cpumask); + break; + } + } +} + +static int intel_cqm_cpu_notifier(struct notifier_block *nb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_UP_PREPARE: + intel_cqm_cpu_prepare(cpu); + break; + case CPU_DOWN_PREPARE: + intel_cqm_cpu_exit(cpu); + break; + case CPU_STARTING: + cqm_pick_event_reader(cpu); + break; + } + + return NOTIFY_OK; +} + +static const struct x86_cpu_id intel_cqm_match[] = { + { .vendor = X86_VENDOR_INTEL, .feature = X86_FEATURE_CQM_OCCUP_LLC }, + {} +}; + +static int __init intel_cqm_init(void) +{ + char *str, scale[20]; + int i, cpu, ret; + + if (!x86_match_cpu(intel_cqm_match)) + return -ENODEV; + + cqm_l3_scale = boot_cpu_data.x86_cache_occ_scale; + + /* + * It's possible that not all resources support the same number + * of RMIDs. Instead of making scheduling much more complicated + * (where we have to match a task's RMID to a cpu that supports + * that many RMIDs) just find the minimum RMIDs supported across + * all cpus. + * + * Also, check that the scales match on all cpus. + */ + cpu_notifier_register_begin(); + + for_each_online_cpu(cpu) { + struct cpuinfo_x86 *c = &cpu_data(cpu); + + if (c->x86_cache_max_rmid < cqm_max_rmid) + cqm_max_rmid = c->x86_cache_max_rmid; + + if (c->x86_cache_occ_scale != cqm_l3_scale) { + pr_err("Multiple LLC scale values, disabling\n"); + ret = -EINVAL; + goto out; + } + } + + snprintf(scale, sizeof(scale), "%u", cqm_l3_scale); + str = kstrdup(scale, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; + goto out; + } + + event_attr_intel_cqm_llc_scale.event_str = str; + + ret = intel_cqm_setup_rmid_cache(); + if (ret) + goto out; + + for_each_online_cpu(i) { + intel_cqm_cpu_prepare(i); + cqm_pick_event_reader(i); + } + + __perf_cpu_notifier(intel_cqm_cpu_notifier); + + ret = perf_pmu_register(&intel_cqm_pmu, "intel_cqm", -1); + + if (ret) + pr_err("Intel CQM perf registration failed: %d\n", ret); + else + pr_info("Intel CQM monitoring enabled\n"); + +out: + cpu_notifier_register_done(); + + return ret; +} +device_initcall(intel_cqm_init); diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 9fc9b0d31442..ca5504c48f4f 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -123,6 +123,13 @@ struct hw_perf_event { /* for tp_event->class */ struct list_head tp_list; }; + struct { /* intel_cqm */ + int cqm_state; + int cqm_rmid; + struct list_head cqm_events_entry; + struct list_head cqm_groups_entry; + struct list_head cqm_group_entry; + }; #ifdef CONFIG_HAVE_HW_BREAKPOINT struct { /* breakpoint */ /* -- cgit v1.2.3 From bfe1fcd2688f557a6b6a88f59ea7619228728bd7 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 23 Jan 2015 18:45:46 +0000 Subject: perf/x86/intel: Support task events with Intel CQM Add support for task events as well as system-wide events. This change has a big impact on the way that we gather LLC occupancy values in intel_cqm_event_read(). Currently, for system-wide (per-cpu) events we defer processing to userspace which knows how to discard all but one cpu result per package. Things aren't so simple for task events because we need to do the value aggregation ourselves. To do this, we defer updating the LLC occupancy value in event->count from intel_cqm_event_read() and do an SMP cross-call to read values for all packages in intel_cqm_event_count(). We need to ensure that we only do this for one task event per cache group, otherwise we'll report duplicate values. If we're a system-wide event we want to fallback to the default perf_event_count() implementation. Refactor this into a common function so that we don't duplicate the code. Also, introduce PERF_TYPE_INTEL_CQM, since we need a way to track an event's task (if the event isn't per-cpu) inside of the Intel CQM PMU driver. This task information is only availble in the upper layers of the perf infrastructure. Other perf backends stash the target task in event->hw.*target so we need to do something similar. The task is used to determine whether events should share a cache group and an RMID. Signed-off-by: Matt Fleming Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kanaka Juvva Cc: Linus Torvalds Cc: Vikas Shivappa Cc: linux-api@vger.kernel.org Link: http://lkml.kernel.org/r/1422038748-21397-8-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_cqm.c | 195 +++++++++++++++++++++++++---- include/linux/perf_event.h | 1 + include/uapi/linux/perf_event.h | 1 + kernel/events/core.c | 2 + 4 files changed, 178 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c index b5d9d746dbc0..8003d87afd89 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c +++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c @@ -182,23 +182,124 @@ fail: /* * Determine if @a and @b measure the same set of tasks. + * + * If @a and @b measure the same set of tasks then we want to share a + * single RMID. */ static bool __match_event(struct perf_event *a, struct perf_event *b) { + /* Per-cpu and task events don't mix */ if ((a->attach_state & PERF_ATTACH_TASK) != (b->attach_state & PERF_ATTACH_TASK)) return false; - /* not task */ +#ifdef CONFIG_CGROUP_PERF + if (a->cgrp != b->cgrp) + return false; +#endif + + /* If not task event, we're machine wide */ + if (!(b->attach_state & PERF_ATTACH_TASK)) + return true; + + /* + * Events that target same task are placed into the same cache group. + */ + if (a->hw.cqm_target == b->hw.cqm_target) + return true; + + /* + * Are we an inherited event? + */ + if (b->parent == a) + return true; + + return false; +} + +#ifdef CONFIG_CGROUP_PERF +static inline struct perf_cgroup *event_to_cgroup(struct perf_event *event) +{ + if (event->attach_state & PERF_ATTACH_TASK) + return perf_cgroup_from_task(event->hw.cqm_target); - return true; /* if not task, we're machine wide */ + return event->cgrp; } +#endif /* * Determine if @a's tasks intersect with @b's tasks + * + * There are combinations of events that we explicitly prohibit, + * + * PROHIBITS + * system-wide -> cgroup and task + * cgroup -> system-wide + * -> task in cgroup + * task -> system-wide + * -> task in cgroup + * + * Call this function before allocating an RMID. */ static bool __conflict_event(struct perf_event *a, struct perf_event *b) { +#ifdef CONFIG_CGROUP_PERF + /* + * We can have any number of cgroups but only one system-wide + * event at a time. + */ + if (a->cgrp && b->cgrp) { + struct perf_cgroup *ac = a->cgrp; + struct perf_cgroup *bc = b->cgrp; + + /* + * This condition should have been caught in + * __match_event() and we should be sharing an RMID. + */ + WARN_ON_ONCE(ac == bc); + + if (cgroup_is_descendant(ac->css.cgroup, bc->css.cgroup) || + cgroup_is_descendant(bc->css.cgroup, ac->css.cgroup)) + return true; + + return false; + } + + if (a->cgrp || b->cgrp) { + struct perf_cgroup *ac, *bc; + + /* + * cgroup and system-wide events are mutually exclusive + */ + if ((a->cgrp && !(b->attach_state & PERF_ATTACH_TASK)) || + (b->cgrp && !(a->attach_state & PERF_ATTACH_TASK))) + return true; + + /* + * Ensure neither event is part of the other's cgroup + */ + ac = event_to_cgroup(a); + bc = event_to_cgroup(b); + if (ac == bc) + return true; + + /* + * Must have cgroup and non-intersecting task events. + */ + if (!ac || !bc) + return false; + + /* + * We have cgroup and task events, and the task belongs + * to a cgroup. Check for for overlap. + */ + if (cgroup_is_descendant(ac->css.cgroup, bc->css.cgroup) || + cgroup_is_descendant(bc->css.cgroup, ac->css.cgroup)) + return true; + + return false; + } +#endif /* * If one of them is not a task, same story as above with cgroups. */ @@ -245,9 +346,16 @@ static int intel_cqm_setup_event(struct perf_event *event, static void intel_cqm_event_read(struct perf_event *event) { - unsigned long rmid = event->hw.cqm_rmid; + unsigned long rmid; u64 val; + /* + * Task events are handled by intel_cqm_event_count(). + */ + if (event->cpu == -1) + return; + + rmid = event->hw.cqm_rmid; val = __rmid_read(rmid); /* @@ -259,6 +367,63 @@ static void intel_cqm_event_read(struct perf_event *event) local64_set(&event->count, val); } +struct rmid_read { + unsigned int rmid; + atomic64_t value; +}; + +static void __intel_cqm_event_count(void *info) +{ + struct rmid_read *rr = info; + u64 val; + + val = __rmid_read(rr->rmid); + + if (val & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL)) + return; + + atomic64_add(val, &rr->value); +} + +static inline bool cqm_group_leader(struct perf_event *event) +{ + return !list_empty(&event->hw.cqm_groups_entry); +} + +static u64 intel_cqm_event_count(struct perf_event *event) +{ + struct rmid_read rr = { + .rmid = event->hw.cqm_rmid, + .value = ATOMIC64_INIT(0), + }; + + /* + * We only need to worry about task events. System-wide events + * are handled like usual, i.e. entirely with + * intel_cqm_event_read(). + */ + if (event->cpu != -1) + return __perf_event_count(event); + + /* + * Only the group leader gets to report values. This stops us + * reporting duplicate values to userspace, and gives us a clear + * rule for which task gets to report the values. + * + * Note that it is impossible to attribute these values to + * specific packages - we forfeit that ability when we create + * task events. + */ + if (!cqm_group_leader(event)) + return 0; + + on_each_cpu_mask(&cqm_cpumask, __intel_cqm_event_count, &rr, 1); + + local64_set(&event->count, atomic64_read(&rr.value)); + + return __perf_event_count(event); +} + static void intel_cqm_event_start(struct perf_event *event, int mode) { struct intel_cqm_state *state = this_cpu_ptr(&cqm_state); @@ -344,7 +509,7 @@ static void intel_cqm_event_destroy(struct perf_event *event) /* * And we're the group leader.. */ - if (!list_empty(&event->hw.cqm_groups_entry)) { + if (cqm_group_leader(event)) { /* * If there was a group_other, make that leader, otherwise * destroy the group and return the RMID. @@ -365,17 +530,6 @@ static void intel_cqm_event_destroy(struct perf_event *event) static struct pmu intel_cqm_pmu; -/* - * XXX there's a bit of a problem in that we cannot simply do the one - * event per node as one would want, since that one event would one get - * scheduled on the one cpu. But we want to 'schedule' the RMID on all - * CPUs. - * - * This means we want events for each CPU, however, that generates a lot - * of duplicate values out to userspace -- this is not to be helped - * unless we want to change the core code in some way. Fore more info, - * see intel_cqm_event_read(). - */ static int intel_cqm_event_init(struct perf_event *event) { struct perf_event *group = NULL; @@ -387,9 +541,6 @@ static int intel_cqm_event_init(struct perf_event *event) if (event->attr.config & ~QOS_EVENT_MASK) return -EINVAL; - if (event->cpu == -1) - return -EINVAL; - /* unsupported modes and filters */ if (event->attr.exclude_user || event->attr.exclude_kernel || @@ -407,7 +558,8 @@ static int intel_cqm_event_init(struct perf_event *event) mutex_lock(&cache_mutex); - err = intel_cqm_setup_event(event, &group); /* will also set rmid */ + /* Will also set rmid */ + err = intel_cqm_setup_event(event, &group); if (err) goto out; @@ -470,6 +622,7 @@ static struct pmu intel_cqm_pmu = { .start = intel_cqm_event_start, .stop = intel_cqm_event_stop, .read = intel_cqm_event_read, + .count = intel_cqm_event_count, }; static inline void cqm_pick_event_reader(int cpu) @@ -599,8 +752,8 @@ static int __init intel_cqm_init(void) __perf_cpu_notifier(intel_cqm_cpu_notifier); - ret = perf_pmu_register(&intel_cqm_pmu, "intel_cqm", -1); - + ret = perf_pmu_register(&intel_cqm_pmu, "intel_cqm", + PERF_TYPE_INTEL_CQM); if (ret) pr_err("Intel CQM perf registration failed: %d\n", ret); else diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ca5504c48f4f..dac4c2831d82 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -129,6 +129,7 @@ struct hw_perf_event { struct list_head cqm_events_entry; struct list_head cqm_groups_entry; struct list_head cqm_group_entry; + struct task_struct *cqm_target; }; #ifdef CONFIG_HAVE_HW_BREAKPOINT struct { /* breakpoint */ diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 1e3cd07cf76e..3c8b45de57ec 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -32,6 +32,7 @@ enum perf_type_id { PERF_TYPE_HW_CACHE = 3, PERF_TYPE_RAW = 4, PERF_TYPE_BREAKPOINT = 5, + PERF_TYPE_INTEL_CQM = 6, PERF_TYPE_MAX, /* non-ABI */ }; diff --git a/kernel/events/core.c b/kernel/events/core.c index 1fc3bae5904a..71109a045450 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7181,6 +7181,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, else if (attr->type == PERF_TYPE_BREAKPOINT) event->hw.bp_target = task; #endif + else if (attr->type == PERF_TYPE_INTEL_CQM) + event->hw.cqm_target = task; } if (!overflow_handler && parent_event) { -- cgit v1.2.3 From b73adef67765b72f2a0d01ef15aff9d784dc85da Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 24 Feb 2015 13:15:33 -0800 Subject: net: dsa: integrate with SWITCHDEV for HW bridging In order to support bridging offloads in DSA switch drivers, select NET_SWITCHDEV to get access to the port_stp_update and parent_get_id NDOs that we are required to implement. To facilitate the integratation at the DSA driver level, we implement 3 types of operations: - port_join_bridge - port_leave_bridge - port_stp_update DSA will resolve which switch ports that are currently bridge port members as some Switch hardware/drivers need to know about that to limit the register programming to just the relevant registers (especially for slow MDIO buses). We also take care of setting the correct STP state when slave network devices are brought up/down while being bridge members. Finally, when a port is leaving the bridge, we make sure we set in BR_STATE_FORWARDING state, otherwise the bridge layer would leave it disabled as a result of having left the bridge. Signed-off-by: Florian Fainelli Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: David S. Miller --- include/net/dsa.h | 10 ++++ net/dsa/Kconfig | 1 + net/dsa/dsa.c | 7 +++ net/dsa/dsa_priv.h | 4 ++ net/dsa/slave.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+) (limited to 'include') diff --git a/include/net/dsa.h b/include/net/dsa.h index ed3c34bbb67a..92be34791963 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -275,6 +275,16 @@ struct dsa_switch_driver { int (*get_regs_len)(struct dsa_switch *ds, int port); void (*get_regs)(struct dsa_switch *ds, int port, struct ethtool_regs *regs, void *p); + + /* + * Bridge integration + */ + int (*port_join_bridge)(struct dsa_switch *ds, int port, + u32 br_port_mask); + int (*port_leave_bridge)(struct dsa_switch *ds, int port, + u32 br_port_mask); + int (*port_stp_update)(struct dsa_switch *ds, int port, + u8 state); }; void register_switch_driver(struct dsa_switch_driver *type); diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 5f8ac404535b..b45206e8dd3e 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -8,6 +8,7 @@ config NET_DSA tristate depends on HAVE_NET_DSA select PHYLIB + select NET_SWITCHDEV if NET_DSA diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index fc1813140be6..9c208f0dab08 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -826,6 +826,10 @@ static struct packet_type dsa_pack_type __read_mostly = { .func = dsa_switch_rcv, }; +static struct notifier_block dsa_netdevice_nb __read_mostly = { + .notifier_call = dsa_slave_netdevice_event, +}; + #ifdef CONFIG_PM_SLEEP static int dsa_suspend(struct device *d) { @@ -884,6 +888,8 @@ static int __init dsa_init_module(void) { int rc; + register_netdevice_notifier(&dsa_netdevice_nb); + rc = platform_driver_register(&dsa_driver); if (rc) return rc; @@ -896,6 +902,7 @@ module_init(dsa_init_module); static void __exit dsa_cleanup_module(void) { + unregister_netdevice_notifier(&dsa_netdevice_nb); dev_remove_pack(&dsa_pack_type); platform_driver_unregister(&dsa_driver); } diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 7eb1a6acd46c..d5f1f9b862ea 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -45,6 +45,8 @@ struct dsa_slave_priv { int old_link; int old_pause; int old_duplex; + + struct net_device *bridge_dev; }; /* dsa.c */ @@ -57,6 +59,8 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, int port, char *name); int dsa_slave_suspend(struct net_device *slave_dev); int dsa_slave_resume(struct net_device *slave_dev); +int dsa_slave_netdevice_event(struct notifier_block *unused, + unsigned long event, void *ptr); /* tag_dsa.c */ extern const struct dsa_device_ops dsa_netdev_ops; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 5be4c928c9c9..b5a4d8974b76 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -10,10 +10,13 @@ #include #include +#include #include #include #include #include +#include +#include #include "dsa_priv.h" /* slave mii_bus handling ***************************************************/ @@ -60,11 +63,18 @@ static int dsa_slave_init(struct net_device *dev) return 0; } +static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p) +{ + return !!p->bridge_dev; +} + static int dsa_slave_open(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = p->parent->dst->master_netdev; struct dsa_switch *ds = p->parent; + u8 stp_state = dsa_port_is_bridged(p) ? + BR_STATE_BLOCKING : BR_STATE_FORWARDING; int err; if (!(master->flags & IFF_UP)) @@ -93,6 +103,9 @@ static int dsa_slave_open(struct net_device *dev) goto clear_promisc; } + if (ds->drv->port_stp_update) + ds->drv->port_stp_update(ds, p->port, stp_state); + if (p->phy) phy_start(p->phy); @@ -133,6 +146,9 @@ static int dsa_slave_close(struct net_device *dev) if (ds->drv->port_disable) ds->drv->port_disable(ds, p->port, p->phy); + if (ds->drv->port_stp_update) + ds->drv->port_stp_update(ds, p->port, BR_STATE_DISABLED); + return 0; } @@ -194,6 +210,95 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } +/* Return a bitmask of all ports being currently bridged within a given bridge + * device. Note that on leave, the mask will still return the bitmask of ports + * currently bridged, prior to port removal, and this is exactly what we want. + */ +static u32 dsa_slave_br_port_mask(struct dsa_switch *ds, + struct net_device *bridge) +{ + struct dsa_slave_priv *p; + unsigned int port; + u32 mask = 0; + + for (port = 0; port < DSA_MAX_PORTS; port++) { + if (!((1 << port) & ds->phys_port_mask)) + continue; + + if (!ds->ports[port]) + continue; + + p = netdev_priv(ds->ports[port]); + + if (ds->ports[port]->priv_flags & IFF_BRIDGE_PORT && + p->bridge_dev == bridge) + mask |= 1 << port; + } + + return mask; +} + +static int dsa_slave_stp_update(struct net_device *dev, u8 state) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + int ret = -EOPNOTSUPP; + + if (ds->drv->port_stp_update) + ret = ds->drv->port_stp_update(ds, p->port, state); + + return ret; +} + +static int dsa_slave_bridge_port_join(struct net_device *dev, + struct net_device *br) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + int ret = -EOPNOTSUPP; + + p->bridge_dev = br; + + if (ds->drv->port_join_bridge) + ret = ds->drv->port_join_bridge(ds, p->port, + dsa_slave_br_port_mask(ds, br)); + + return ret; +} + +static int dsa_slave_bridge_port_leave(struct net_device *dev) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + int ret = -EOPNOTSUPP; + + + if (ds->drv->port_leave_bridge) + ret = ds->drv->port_leave_bridge(ds, p->port, + dsa_slave_br_port_mask(ds, p->bridge_dev)); + + p->bridge_dev = NULL; + + /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, + * so allow it to be in BR_STATE_FORWARDING to be kept functional + */ + dsa_slave_stp_update(dev, BR_STATE_FORWARDING); + + return ret; +} + +static int dsa_slave_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + + psid->id_len = sizeof(ds->index); + memcpy(&psid->id, &ds->index, psid->id_len); + + return 0; +} + static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); @@ -470,6 +575,8 @@ static const struct net_device_ops dsa_slave_netdev_ops = { .ndo_set_rx_mode = dsa_slave_set_rx_mode, .ndo_set_mac_address = dsa_slave_set_mac_address, .ndo_do_ioctl = dsa_slave_ioctl, + .ndo_switch_parent_id_get = dsa_slave_parent_id_get, + .ndo_switch_port_stp_update = dsa_slave_stp_update, }; static void dsa_slave_adjust_link(struct net_device *dev) @@ -684,3 +791,45 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, return 0; } + +static bool dsa_slave_dev_check(struct net_device *dev) +{ + return dev->netdev_ops == &dsa_slave_netdev_ops; +} + +static int dsa_slave_master_changed(struct net_device *dev) +{ + struct net_device *master = netdev_master_upper_dev_get(dev); + int err = 0; + + if (master && master->rtnl_link_ops && + !strcmp(master->rtnl_link_ops->kind, "bridge")) + err = dsa_slave_bridge_port_join(dev, master); + else + err = dsa_slave_bridge_port_leave(dev); + + return err; +} + +int dsa_slave_netdevice_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev; + int err = 0; + + switch (event) { + case NETDEV_CHANGEUPPER: + dev = netdev_notifier_info_to_dev(ptr); + if (!dsa_slave_dev_check(dev)) + goto out; + + err = dsa_slave_master_changed(dev); + if (err) + netdev_warn(dev, "failed to reflect master change\n"); + + break; + } + +out: + return NOTIFY_DONE; +} -- cgit v1.2.3 From d79d21073626cf022943e5c4c10a97cdf7cb8465 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 24 Feb 2015 23:02:02 -0800 Subject: net: dsa: Introduce dsa_is_port_initialized To avoid race conditions when using the ds->ports[] array, we need to check if the accessed port has been initialized. Introduce and use helper function dsa_is_port_initialized for that purpose and use it where needed. Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller --- include/net/dsa.h | 5 +++++ net/dsa/dsa.c | 4 ++-- net/dsa/slave.c | 5 +---- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/dsa.h b/include/net/dsa.h index 92be34791963..c542c131d551 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -165,6 +165,11 @@ static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port); } +static inline bool dsa_is_port_initialized(struct dsa_switch *ds, int p) +{ + return ds->phys_port_mask & (1 << p) && ds->ports[p]; +} + static inline u8 dsa_upstream_port(struct dsa_switch *ds) { struct dsa_switch_tree *dst = ds->dst; diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 9c208f0dab08..a1d1f0775bea 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -374,7 +374,7 @@ static int dsa_switch_suspend(struct dsa_switch *ds) /* Suspend slave network devices */ for (i = 0; i < DSA_MAX_PORTS; i++) { - if (!(ds->phys_port_mask & (1 << i))) + if (!dsa_is_port_initialized(ds, i)) continue; ret = dsa_slave_suspend(ds->ports[i]); @@ -400,7 +400,7 @@ static int dsa_switch_resume(struct dsa_switch *ds) /* Resume slave network devices */ for (i = 0; i < DSA_MAX_PORTS; i++) { - if (!(ds->phys_port_mask & (1 << i))) + if (!dsa_is_port_initialized(ds, i)) continue; ret = dsa_slave_resume(ds->ports[i]); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index b5a4d8974b76..a47305c72fcc 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -222,10 +222,7 @@ static u32 dsa_slave_br_port_mask(struct dsa_switch *ds, u32 mask = 0; for (port = 0; port < DSA_MAX_PORTS; port++) { - if (!((1 << port) & ds->phys_port_mask)) - continue; - - if (!ds->ports[port]) + if (!dsa_is_port_initialized(ds, port)) continue; p = netdev_priv(ds->ports[port]); -- cgit v1.2.3 From 737eb0301f296d55c22350c6968ff1ef51bacb5f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 20 Feb 2015 14:53:46 +0000 Subject: genirq / PM: better describe IRQF_NO_SUSPEND semantics The IRQF_NO_SUSPEND flag is intended to be used for interrupts required to be enabled during the suspend-resume cycle. This mostly consists of IPIs and timer interrupts, potentially including chained irqchip interrupts if these are necessary to handle timers or IPIs. If an interrupt does not fall into one of the aforementioned categories, requesting it with IRQF_NO_SUSPEND is likely incorrect. Using IRQF_NO_SUSPEND does not guarantee that the interrupt can wake the system from a suspended state. For an interrupt to be able to trigger a wakeup, it may be necessary to program various components of the system. In these cases it is necessary to use {enable,disabled}_irq_wake. Unfortunately, several drivers assume that IRQF_NO_SUSPEND ensures that an IRQ can wake up the system, and the documentation can be read ambiguously w.r.t. this property. This patch updates the documentation regarding IRQF_NO_SUSPEND to make this caveat explicit, hopefully making future misuse rarer. Cleanup of existing misuse will occur as part of later patch series. Signed-off-by: Mark Rutland Acked-by: Peter Zijlstra (Intel) Signed-off-by: Rafael J. Wysocki --- Documentation/power/suspend-and-interrupts.txt | 6 ++++-- include/linux/interrupt.h | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/Documentation/power/suspend-and-interrupts.txt b/Documentation/power/suspend-and-interrupts.txt index 2f9c5a5fcb25..50493c9284b4 100644 --- a/Documentation/power/suspend-and-interrupts.txt +++ b/Documentation/power/suspend-and-interrupts.txt @@ -40,8 +40,10 @@ but also to IPIs and to some other special-purpose interrupts. The IRQF_NO_SUSPEND flag is used to indicate that to the IRQ subsystem when requesting a special-purpose interrupt. It causes suspend_device_irqs() to -leave the corresponding IRQ enabled so as to allow the interrupt to work all -the time as expected. +leave the corresponding IRQ enabled so as to allow the interrupt to work as +expected during the suspend-resume cycle, but does not guarantee that the +interrupt will wake the system from a suspended state -- for such cases it is +necessary to use enable_irq_wake(). Note that the IRQF_NO_SUSPEND flag affects the entire IRQ and not just one user of it. Thus, if the IRQ is shared, all of the interrupt handlers installed diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index d9b05b5bf8c7..606771c7cac2 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -52,7 +52,9 @@ * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. * Used by threaded interrupts which need to keep the * irq line disabled until the threaded handler has been run. - * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend + * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend. Does not guarantee + * that this interrupt will wake the system from a suspended + * state. See Documentation/power/suspend-and-interrupts.txt * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set * IRQF_NO_THREAD - Interrupt cannot be threaded * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device -- cgit v1.2.3 From 5d8a4219a0795a321606c51582898223db80e874 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 24 Feb 2015 15:33:50 +1100 Subject: power_supply core: support use of devres to register/unregister a power supply. Using devm_power_supply_register allows the unregister to happen automatically on error or final put. Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/power_supply_core.c | 45 +++++++++++++++++++++++++++++++++++++++ include/linux/power_supply.h | 4 ++++ 2 files changed, 49 insertions(+) (limited to 'include') diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 694e8cddd5c1..44c810456212 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -617,6 +617,51 @@ int power_supply_register_no_ws(struct device *parent, struct power_supply *psy) } EXPORT_SYMBOL_GPL(power_supply_register_no_ws); +static void devm_power_supply_release(struct device *dev, void *res) +{ + struct power_supply **psy = res; + + power_supply_unregister(*psy); +} + +int devm_power_supply_register(struct device *parent, struct power_supply *psy) +{ + struct power_supply **ptr = devres_alloc(devm_power_supply_release, + sizeof(*ptr), GFP_KERNEL); + int ret; + + if (!ptr) + return -ENOMEM; + ret = __power_supply_register(parent, psy, true); + if (ret < 0) + devres_free(ptr); + else { + *ptr = psy; + devres_add(parent, ptr); + } + return ret; +} +EXPORT_SYMBOL_GPL(devm_power_supply_register); + +int devm_power_supply_register_no_ws(struct device *parent, struct power_supply *psy) +{ + struct power_supply **ptr = devres_alloc(devm_power_supply_release, + sizeof(*ptr), GFP_KERNEL); + int ret; + + if (!ptr) + return -ENOMEM; + ret = __power_supply_register(parent, psy, false); + if (ret < 0) + devres_free(ptr); + else { + *ptr = psy; + devres_add(parent, ptr); + } + return ret; +} +EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws); + void power_supply_unregister(struct power_supply *psy) { cancel_work_sync(&psy->changed_work); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 096dbced02ac..f606d6b4bd56 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -278,6 +278,10 @@ extern int power_supply_register(struct device *parent, struct power_supply *psy); extern int power_supply_register_no_ws(struct device *parent, struct power_supply *psy); +extern int devm_power_supply_register(struct device *parent, + struct power_supply *psy); +extern int devm_power_supply_register_no_ws(struct device *parent, + struct power_supply *psy); extern void power_supply_unregister(struct power_supply *psy); extern int power_supply_powers(struct power_supply *psy, struct device *dev); -- cgit v1.2.3 From ee376dbdf27728a2f3d30e2ba10fa387cc4c645b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 10 Jan 2015 19:47:10 -0800 Subject: rcu: Consolidate rcu_synchronize and wakeme_after_rcu() There are currently duplicate identical definitions of the rcu_synchronize() structure and the wakeme_after_rcu() function. Thie commit therefore consolidates them. Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 9 +++++++++ kernel/rcu/srcu.c | 17 ----------------- kernel/rcu/update.c | 15 ++++++--------- 3 files changed, 15 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 78097491cd99..3e6afed51051 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -195,6 +195,15 @@ void call_rcu_sched(struct rcu_head *head, void synchronize_sched(void); +/* + * Structure allowing asynchronous waiting on RCU. + */ +struct rcu_synchronize { + struct rcu_head head; + struct completion completion; +}; +void wakeme_after_rcu(struct rcu_head *head); + /** * call_rcu_tasks() - Queue an RCU for invocation task-based grace period * @head: structure to be used for queueing the RCU updates. diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index 445bf8ffe3fb..81f53b504c18 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -402,23 +402,6 @@ void call_srcu(struct srcu_struct *sp, struct rcu_head *head, } EXPORT_SYMBOL_GPL(call_srcu); -struct rcu_synchronize { - struct rcu_head head; - struct completion completion; -}; - -/* - * Awaken the corresponding synchronize_srcu() instance now that a - * grace period has elapsed. - */ -static void wakeme_after_rcu(struct rcu_head *head) -{ - struct rcu_synchronize *rcu; - - rcu = container_of(head, struct rcu_synchronize, head); - complete(&rcu->completion); -} - static void srcu_advance_batches(struct srcu_struct *sp, int trycount); static void srcu_reschedule(struct srcu_struct *sp); diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index e0d31a345ee6..8864ed90f0d7 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -199,16 +199,13 @@ EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held); #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ -struct rcu_synchronize { - struct rcu_head head; - struct completion completion; -}; - -/* - * Awaken the corresponding synchronize_rcu() instance now that a - * grace period has elapsed. +/** + * wakeme_after_rcu() - Callback function to awaken a task after grace period + * @head: Pointer to rcu_head member within rcu_synchronize structure + * + * Awaken the corresponding task now that a grace period has elapsed. */ -static void wakeme_after_rcu(struct rcu_head *head) +void wakeme_after_rcu(struct rcu_head *head) { struct rcu_synchronize *rcu; -- cgit v1.2.3 From a38bb793eaebe1178fbd8ef6ab66ccc062bad505 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 25 Feb 2015 10:23:58 +0200 Subject: OMAPDSS: fix regression with display sysfs files omapdss's sysfs directories for displays used to have 'name' file, giving the name for the display. This file was later renamed to 'display_name' to avoid conflicts with i2c sysfs 'name' file. Looks like at least xserver-xorg-video-omap3 requires the 'name' file to be present. To fix the regression, this patch creates new kobjects for each display, allowing us to create sysfs directories for the displays. This way we have the whole directory for omapdss, and there will be no sysfs file clashes with the underlying display device's sysfs files. We can thus add the 'name' sysfs file back. Signed-off-by: Tomi Valkeinen Tested-by: NeilBrown --- drivers/video/fbdev/omap2/dss/display-sysfs.c | 179 ++++++++++++++------------ include/video/omapdss.h | 1 + 2 files changed, 96 insertions(+), 84 deletions(-) (limited to 'include') diff --git a/drivers/video/fbdev/omap2/dss/display-sysfs.c b/drivers/video/fbdev/omap2/dss/display-sysfs.c index 5a2095a98ed8..12186557a9d4 100644 --- a/drivers/video/fbdev/omap2/dss/display-sysfs.c +++ b/drivers/video/fbdev/omap2/dss/display-sysfs.c @@ -28,44 +28,22 @@ #include