blob: 687254f4db664469d3e3b1867dfb6b6d67b56501 [file] [log] [blame]
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <errno.h>
#include <platsupport/io.h>
#include <utils/util.h>
#include <clockserver_client.h>
typedef struct clockserver_interface_data {
ps_io_ops_t *io_ops;
int (*clockserver_init_clock)(clk_id_t id);
int (*clockserver_set_gate_mode)(clock_gate_t gate, clock_gate_mode_t mode);
freq_t (*clockserver_get_freq)(clk_id_t clk_id);
freq_t (*clockserver_set_freq)(clk_id_t clk_id, freq_t hz);
int (*clockserver_register_child)(clk_id_t parent, clk_id_t child);
} clockserver_interface_data_t;
static clockserver_interface_data_t clockserver_private_data;
/* Note: No clk_t->init or clk_t->recal as these are handled by the server,
* also no register child for now as there are limitations */
static freq_t clockserver_get_freq_wrapper(clk_t *clk)
{
clock_sys_t *clock_sys = clk->clk_sys;
clockserver_interface_data_t *clockserver_data = clock_sys->priv;
return clockserver_data->clockserver_get_freq(clk->id);
}
static freq_t clockserver_set_freq_wrapper(clk_t *clk, freq_t hz)
{
clock_sys_t *clock_sys = clk->clk_sys;
clockserver_interface_data_t *clockserver_data = clock_sys->priv;
freq_t set_freq = clockserver_data->clockserver_set_freq(clk->id, hz);
/* Set the requested frequency */
clk->req_freq = hz;
return set_freq;
}
static clk_t *clockserver_get_clock_wrapper(clock_sys_t *clock_sys, enum clk_id id)
{
clockserver_interface_data_t *clockserver_data = clock_sys->priv;
int error = clockserver_data->clockserver_init_clock(id);
if (error) {
return NULL;
}
/* Allocate a clk_t structure and fill it in */
clk_t *ret_clk = NULL;
error = ps_calloc(&clockserver_data->io_ops->malloc_ops, 1, sizeof(clk_t), (void **) &ret_clk);
if (error) {
return NULL;
}
ret_clk->id = id;
/* 'priv' needs to be setup for the function wrappers to not throw EINVAL,
* we actually use 'priv' */
ret_clk->priv = (void *)((uintptr_t) 0xDEADBEEF);
ret_clk->clk_sys = clock_sys;
ret_clk->get_freq = clockserver_get_freq_wrapper;
ret_clk->set_freq = clockserver_set_freq_wrapper;
return ret_clk;
}
static int clockserver_gate_enable_wrapper(clock_sys_t *clock_sys, enum clock_gate gate,
enum clock_gate_mode mode)
{
clockserver_interface_data_t *clockserver_data = clock_sys->priv;
return clockserver_data->clockserver_set_gate_mode(gate, mode);
}
int clockserver_interface_init(ps_io_ops_t *io_ops,
int (*clockserver_init_clock)(clk_id_t id),
int (*clockserver_set_gate_mode)(clock_gate_t gate, clock_gate_mode_t mode),
freq_t (*clockserver_get_freq)(clk_id_t clk_id),
freq_t (*clockserver_set_freq)(clk_id_t clk_id, freq_t hz),
int (*clockserver_register_child)(clk_id_t parent, clk_id_t child),
clock_sys_t *clock_sys)
{
if (!io_ops) {
ZF_LOGE("io_ops is NULL");
return -EINVAL;
}
if (!clockserver_init_clock) {
ZF_LOGE("clockserver_init_clock is NULL");
return -EINVAL;
}
if (!clockserver_set_gate_mode) {
ZF_LOGE("clockserver_set_gate_mode is NULL");
return -EINVAL;
}
if (!clockserver_get_freq) {
ZF_LOGE("clockserver_get_freq is NULL");
return -EINVAL;
}
if (!clockserver_set_freq) {
ZF_LOGE("clockserver_set_freq is NULL");
return -EINVAL;
}
if (!clockserver_register_child) {
ZF_LOGE("clockserver_register_child is NULL");
return -EINVAL;
}
if (!clock_sys) {
ZF_LOGE("provided clock_sys_t is NULL");
return -EINVAL;
}
clockserver_private_data.io_ops = io_ops;
clockserver_private_data.clockserver_init_clock = clockserver_init_clock;
clockserver_private_data.clockserver_set_gate_mode = clockserver_set_gate_mode;
clockserver_private_data.clockserver_get_freq = clockserver_get_freq;
clockserver_private_data.clockserver_set_freq = clockserver_set_freq;
clockserver_private_data.clockserver_register_child = clockserver_register_child;
clock_sys->priv = &clockserver_private_data;
clock_sys->get_clock = clockserver_get_clock_wrapper;
clock_sys->gate_enable = clockserver_gate_enable_wrapper;
return 0;
}