# HG changeset patch # User Paul Boddie # Date 1610837259 -3600 # Node ID 47295373521e6b2efecdd48d31c323f8dc934c47 # Parent c09f21715d8d3d7b7202abb34c462c611cac9e1e Introduced generic clock control methods to the CPM library and device. diff -r c09f21715d8d -r 47295373521e pkg/devices/Makefile --- a/pkg/devices/Makefile Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/Makefile Sat Jan 16 23:47:39 2021 +0100 @@ -17,6 +17,6 @@ input: keypad lib keypad: lib util lcd: display lib util -lib: util +lib: include util pwm: lib util spi: lib util diff -r c09f21715d8d -r 47295373521e pkg/devices/cpm/src/jz4730/cpm-jz4730.cc --- a/pkg/devices/cpm/src/jz4730/cpm-jz4730.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/cpm/src/jz4730/cpm-jz4730.cc Sat Jan 16 23:47:39 2021 +0100 @@ -1,7 +1,7 @@ /* * JZ4730 CPM server. * - * Copyright (C) 2018, 2020 Paul Boddie + * Copyright (C) 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -63,15 +63,21 @@ return L4_EOK; } - long start_lcd() + long have_clock(enum Clock_identifiers clock, int *enabled) { - _chip->start_lcd(); + *enabled = _chip->have_clock(clock); return L4_EOK; } - long stop_lcd() + long start_clock(enum Clock_identifiers clock) { - _chip->stop_lcd(); + _chip->start_clock(clock); + return L4_EOK; + } + + long stop_clock(enum Clock_identifiers clock) + { + _chip->stop_clock(clock); return L4_EOK; } diff -r c09f21715d8d -r 47295373521e pkg/devices/cpm/src/jz4740/cpm-jz4740.cc --- a/pkg/devices/cpm/src/jz4740/cpm-jz4740.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/cpm/src/jz4740/cpm-jz4740.cc Sat Jan 16 23:47:39 2021 +0100 @@ -1,7 +1,7 @@ /* * JZ4740 CPM server. * - * Copyright (C) 2018, 2020 Paul Boddie + * Copyright (C) 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -63,15 +63,21 @@ return L4_EOK; } - long start_lcd() + long have_clock(enum Clock_identifiers clock, int *enabled) { - _chip->start_lcd(); + *enabled = _chip->have_clock(clock); return L4_EOK; } - long stop_lcd() + long start_clock(enum Clock_identifiers clock) { - _chip->stop_lcd(); + _chip->start_clock(clock); + return L4_EOK; + } + + long stop_clock(enum Clock_identifiers clock) + { + _chip->stop_clock(clock); return L4_EOK; } diff -r c09f21715d8d -r 47295373521e pkg/devices/cpm/src/jz4780/cpm-jz4780.cc --- a/pkg/devices/cpm/src/jz4780/cpm-jz4780.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/cpm/src/jz4780/cpm-jz4780.cc Sat Jan 16 23:47:39 2021 +0100 @@ -1,7 +1,7 @@ /* * JZ4780 CPM server. * - * Copyright (C) 2018, 2020 Paul Boddie + * Copyright (C) 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -75,27 +75,21 @@ return L4_EOK; } - long start_hdmi() + long have_clock(enum Clock_identifiers clock, int *enabled) { - _chip->start_hdmi(); + *enabled = _chip->have_clock(clock); return L4_EOK; } - long stop_hdmi() + long start_clock(enum Clock_identifiers clock) { - _chip->stop_hdmi(); + _chip->start_clock(clock); return L4_EOK; } - long start_lcd() + long stop_clock(enum Clock_identifiers clock) { - _chip->start_lcd(); - return L4_EOK; - } - - long stop_lcd() - { - _chip->stop_lcd(); + _chip->stop_clock(clock); return L4_EOK; } diff -r c09f21715d8d -r 47295373521e pkg/devices/display/src/ci20/display-ci20_hdmi.cc --- a/pkg/devices/display/src/ci20/display-ci20_hdmi.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/display/src/ci20/display-ci20_hdmi.cc Sat Jan 16 23:47:39 2021 +0100 @@ -64,9 +64,9 @@ /* Start the HDMI peripheral. */ - cpm_device->stop_hdmi(); + cpm_device->stop_clock(Clock_hdmi); cpm_device->set_hdmi_frequency(27000000); - cpm_device->start_hdmi(); + cpm_device->start_clock(Clock_hdmi); /* Load the panel data from the configured library. */ diff -r c09f21715d8d -r 47295373521e pkg/devices/idl/cpm.idl --- a/pkg/devices/idl/cpm.idl Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/idl/cpm.idl Sat Jan 16 23:47:39 2021 +0100 @@ -1,3 +1,4 @@ +#include #include #include @@ -13,13 +14,11 @@ void set_lcd_frequencies(in uint32_t pclk, in uint8_t multiplier); - void start_hdmi(); - - void stop_hdmi(); + void have_clock(in enum Clock_identifiers clock, out int enabled); - void start_lcd(); + void start_clock(in enum Clock_identifiers clock); - void stop_lcd(); + void stop_clock(in enum Clock_identifiers clock); void update_output_frequency(); }; diff -r c09f21715d8d -r 47295373521e pkg/devices/include/clocks.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/include/clocks.h Sat Jan 16 23:47:39 2021 +0100 @@ -0,0 +1,55 @@ +/* + * Clock identifiers for clock and power management. + * + * Copyright (C) 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum Clock_identifiers +{ + Clock_aic_bitclk, + Clock_aic_pclk, + Clock_cim, + Clock_dma, + Clock_emac, + Clock_hdmi, + Clock_i2c, + Clock_kbc, + Clock_lcd, + Clock_msc, + Clock_pmw0, + Clock_pwm1, + Clock_scc, + Clock_smb0, + Clock_smb1, + Clock_smb2, + Clock_smb3, + Clock_smb4, + Clock_ssi, + Clock_timer, + Clock_uart0, + Clock_uart1, + Clock_uart2, + Clock_uart3, + Clock_udc, + Clock_uhc, + Clock_uprt, +}; + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r c09f21715d8d -r 47295373521e pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc --- a/pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc Sat Jan 16 23:47:39 2021 +0100 @@ -1,7 +1,7 @@ /* * Common LCD device support for the JZ4740 and related SoCs. * - * Copyright (C) 2018, 2020 Paul Boddie + * Copyright (C) 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -57,7 +57,7 @@ { uint32_t pclk = lcd_chip->get_pixel_clock(); - cpm_device->stop_lcd(); + cpm_device->stop_clock(Clock_lcd); // Original comment: LCDClock > 2.5*Pixclock // However, the documentation indicates that a TFT panel needs a device clock @@ -66,7 +66,7 @@ cpm_device->set_lcd_frequencies(pclk, 3); cpm_device->update_output_frequency(); - cpm_device->start_lcd(); + cpm_device->start_clock(Clock_lcd); l4_sleep(1); // 1ms == 1000us } diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/Makefile --- a/pkg/devices/lib/Makefile Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/Makefile Sat Jan 16 23:47:39 2021 +0100 @@ -1,11 +1,12 @@ PKGDIR ?= .. L4DIR ?= $(PKGDIR)/../.. -TARGET := common cpm gpio hdmi i2c keypad lcd panel pwm +TARGET := common cpm dma gpio hdmi i2c keypad lcd panel pwm include $(L4DIR)/mk/subdir.mk cpm: common +dma: common gpio: common hdmi: panel i2c: common diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/cpm/include/cpm-jz4730.h --- a/pkg/devices/lib/cpm/include/cpm-jz4730.h Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/cpm/include/cpm-jz4730.h Sat Jan 16 23:47:39 2021 +0100 @@ -1,7 +1,7 @@ /* * CPM (clock and power management) support for the JZ4730. * - * Copyright (C) 2017, 2018, 2020 Paul Boddie + * Copyright (C) 2017, 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -45,12 +45,13 @@ int pll_enabled(); int pll_bypassed(); + // Clock control. + + uint32_t get_clock_gate_value(enum Clock_identifiers clock); + public: Cpm_jz4730_chip(l4_addr_t addr, uint32_t exclk_freq); - int have_clock(); - void start_clock(); - int have_pll(); uint16_t get_multiplier(); @@ -71,11 +72,9 @@ void set_lcd_pixel_divider(uint16_t division); void set_lcd_frequencies(uint32_t pclk, uint8_t ratio); - void start_i2c(); - void stop_i2c(); - - void start_lcd(); - void stop_lcd(); + int have_clock(enum Clock_identifiers clock); + void start_clock(enum Clock_identifiers clock); + void stop_clock(enum Clock_identifiers clock); uint32_t get_pll_frequency(); uint32_t get_output_frequency(); @@ -99,14 +98,9 @@ int jz4730_cpm_have_pll(void *cpm); -int jz4730_cpm_have_clock(void *cpm); -void jz4730_cpm_start_clock(void *cpm); - -void jz4730_cpm_start_i2c(void *cpm); -void jz4730_cpm_stop_i2c(void *cpm); - -void jz4730_cpm_start_lcd(void *cpm); -void jz4730_cpm_stop_lcd(void *cpm); +int jz4730_cpm_have_clock(void *cpm, enum Clock_identifiers clock); +void jz4730_cpm_start_clock(void *cpm, enum Clock_identifiers clock); +void jz4730_cpm_stop_clock(void *cpm, enum Clock_identifiers clock); uint16_t jz4730_cpm_get_lcd_pixel_divider(void *cpm); uint32_t jz4730_cpm_get_lcd_pixel_frequency(void *cpm); diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/cpm/include/cpm-jz4740.h --- a/pkg/devices/lib/cpm/include/cpm-jz4740.h Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/cpm/include/cpm-jz4740.h Sat Jan 16 23:47:39 2021 +0100 @@ -1,5 +1,7 @@ /* - * Copyright (C) 2017, 2018 Paul Boddie + * CPM (clock and power management) support for the JZ4740. + * + * Copyright (C) 2017, 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -43,11 +45,16 @@ int pll_enabled(); int pll_bypassed(); + // Clock control. + + uint32_t get_clock_gate_value(enum Clock_identifiers clock); + public: Cpm_jz4740_chip(l4_addr_t addr, uint32_t exclk_freq); - int have_clock(); - void start_clock(); + int have_clock(enum Clock_identifiers clock); + void start_clock(enum Clock_identifiers clock); + void stop_clock(enum Clock_identifiers clock); int have_pll(); @@ -69,9 +76,6 @@ void set_lcd_pixel_divider(uint16_t division); void set_lcd_frequencies(uint32_t pclk, uint8_t ratio); - void start_lcd(); - void stop_lcd(); - uint32_t get_pll_frequency(); uint32_t get_output_frequency(); void update_output_frequency(); @@ -94,11 +98,9 @@ int jz4740_cpm_have_pll(void *cpm); -int jz4740_cpm_have_clock(void *cpm); -void jz4740_cpm_start_clock(void *cpm); - -void jz4740_cpm_start_lcd(void *cpm); -void jz4740_cpm_stop_lcd(void *cpm); +int jz4740_cpm_have_clock(void *cpm, enum Clock_identifiers clock); +void jz4740_cpm_start_clock(void *cpm, enum Clock_identifiers clock); +void jz4740_cpm_stop_clock(void *cpm, enum Clock_identifiers clock); uint16_t jz4740_cpm_get_lcd_pixel_divider(void *cpm); uint32_t jz4740_cpm_get_lcd_pixel_frequency(void *cpm); diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/cpm/include/cpm-jz4780.h --- a/pkg/devices/lib/cpm/include/cpm-jz4780.h Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/cpm/include/cpm-jz4780.h Sat Jan 16 23:47:39 2021 +0100 @@ -1,5 +1,7 @@ /* - * Copyright (C) 2017, 2018, 2020 Paul Boddie + * CPM (clock and power management) support for the JZ4780. + * + * Copyright (C) 2017, 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -68,10 +70,6 @@ void set_hdmi_divider(uint16_t division); void set_lcd_pixel_divider(uint8_t controller, uint16_t division); - // Clock control. - - void _update_i2c(uint8_t channel, int enable); - // Input frequencies. uint32_t get_pll_frequency(uint32_t pll_reg); @@ -82,12 +80,18 @@ void set_hdmi_source(uint8_t source); void set_lcd_source(uint8_t controller, uint8_t source); + // Clock control. + + uint32_t get_clock_gate_register(enum Clock_identifiers clock); + uint32_t get_clock_gate_value(enum Clock_identifiers clock); + public: void set_pclock_source(uint8_t source); Cpm_jz4780_chip(l4_addr_t addr, uint32_t exclk_freq, uint32_t rtclk_freq); - int have_clock(); - void start_clock(); + int have_clock(enum Clock_identifiers clock); + void start_clock(enum Clock_identifiers clock); + void stop_clock(enum Clock_identifiers clock); // Clock divider values. @@ -99,17 +103,6 @@ uint8_t get_lcd_pixel_divider(uint8_t controller = 0); uint8_t get_memory_divider(); - // Clock control. - - void start_hdmi(); - void stop_hdmi(); - - void start_lcd(); - void stop_lcd(); - - void start_i2c(uint8_t channel); - void stop_i2c(uint8_t channel); - // Input frequencies. uint8_t get_main_source(); @@ -169,14 +162,9 @@ void *jz4780_cpm_init(l4_addr_t cpm_base); -int jz4780_cpm_have_clock(void *cpm); -void jz4780_cpm_start_clock(void *cpm); - -void jz4780_cpm_start_hdmi(void *cpm); -void jz4780_cpm_stop_hdmi(void *cpm); - -void jz4780_cpm_start_lcd(void *cpm); -void jz4780_cpm_stop_lcd(void *cpm); +int jz4780_cpm_have_clock(void *cpm, enum Clock_identifiers clock); +void jz4780_cpm_start_clock(void *cpm, enum Clock_identifiers clock); +void jz4780_cpm_stop_clock(void *cpm, enum Clock_identifiers clock); uint8_t jz4780_cpm_get_cpu_divider(void *cpm); uint8_t jz4780_cpm_get_hclock0_divider(void *cpm); diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/cpm/include/cpm.h --- a/pkg/devices/lib/cpm/include/cpm.h Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/cpm/include/cpm.h Sat Jan 16 23:47:39 2021 +0100 @@ -1,7 +1,7 @@ /* * Clock and power management (CPM) abstractions. * - * Copyright (C) 2017, 2018, 2020 Paul Boddie + * Copyright (C) 2017, 2018, 2020, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -37,13 +38,13 @@ virtual void set_hdmi_frequency(uint32_t) { } - virtual void start_hdmi() { } - virtual void stop_hdmi() { } - virtual void set_lcd_frequencies(uint32_t pclk, uint8_t ratio) = 0; - virtual void start_lcd() = 0; - virtual void stop_lcd() = 0; + virtual int have_clock(enum Clock_identifiers clock) = 0; + + virtual void start_clock(enum Clock_identifiers clock) = 0; + + virtual void stop_clock(enum Clock_identifiers clock) = 0; virtual void update_output_frequency() = 0; }; diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/cpm/src/jz4730.cc --- a/pkg/devices/lib/cpm/src/jz4730.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/cpm/src/jz4730.cc Sat Jan 16 23:47:39 2021 +0100 @@ -103,16 +103,52 @@ // Clock/timer control. +uint32_t +Cpm_jz4730_chip::get_clock_gate_value(enum Clock_identifiers clock) +{ + switch (clock) + { + case Clock_uprt: return (1 << Clock_gate_uprt); + case Clock_udc: return (1 << Clock_gate_udc); + case Clock_cim: return (1 << Clock_gate_cim); + case Clock_kbc: return (1 << Clock_gate_kbc); + case Clock_emac: return (1 << Clock_gate_emac); + case Clock_uart3: return (1 << Clock_gate_uart3); + case Clock_aic_bitclk: return (1 << Clock_gate_aic_bitclk); + case Clock_scc: return (1 << Clock_gate_scc); + case Clock_msc: return (1 << Clock_gate_msc); + case Clock_ssi: return (1 << Clock_gate_ssi); + case Clock_pwm1: return (1 << Clock_gate_pwm1); + case Clock_pmw0: return (1 << Clock_gate_pmw0); + case Clock_aic_pclk: return (1 << Clock_gate_aic_pclk); + case Clock_i2c: return (1 << Clock_gate_i2c); + case Clock_lcd: return (1 << Clock_gate_lcd); + case Clock_uhc: return (1 << Clock_gate_uhc); + case Clock_dma: return (1 << Clock_gate_dmac); + case Clock_timer: return (1 << Clock_gate_timer); + case Clock_uart2: return (1 << Clock_gate_uart2); + case Clock_uart1: return (1 << Clock_gate_uart1); + case Clock_uart0: return (1 << Clock_gate_uart0); + default: return 0; + } +} + int -Cpm_jz4730_chip::have_clock() +Cpm_jz4730_chip::have_clock(enum Clock_identifiers clock) { - return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); + return !(_regs[Clock_gate] & get_clock_gate_value(clock)); } void -Cpm_jz4730_chip::start_clock() +Cpm_jz4730_chip::start_clock(enum Clock_identifiers clock) { - _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); + _regs[Clock_gate] = _regs[Clock_gate] & ~get_clock_gate_value(clock); +} + +void +Cpm_jz4730_chip::stop_clock(enum Clock_identifiers clock) +{ + _regs[Clock_gate] = _regs[Clock_gate] | get_clock_gate_value(clock); } // PLL control. @@ -288,38 +324,6 @@ -// I2C clock control. - -void -Cpm_jz4730_chip::start_i2c() -{ - _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_i2c); -} - -void -Cpm_jz4730_chip::stop_i2c() -{ - _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_i2c); -} - - - -// LCD clock control. - -void -Cpm_jz4730_chip::start_lcd() -{ - _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_lcd); -} - -void -Cpm_jz4730_chip::stop_lcd() -{ - _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_lcd); -} - - - uint32_t Cpm_jz4730_chip::get_pll_frequency() { @@ -403,39 +407,21 @@ } int -jz4730_cpm_have_clock(void *cpm) +jz4730_cpm_have_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->have_clock(); -} - -void -jz4730_cpm_start_clock(void *cpm) -{ - static_cast(cpm)->start_clock(); + return static_cast(cpm)->have_clock(clock); } void -jz4730_cpm_start_i2c(void *cpm) +jz4730_cpm_start_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_i2c(); + static_cast(cpm)->start_clock(clock); } void -jz4730_cpm_stop_i2c(void *cpm) -{ - static_cast(cpm)->stop_i2c(); -} - -void -jz4730_cpm_start_lcd(void *cpm) +jz4730_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_lcd(); -} - -void -jz4730_cpm_stop_lcd(void *cpm) -{ - static_cast(cpm)->stop_lcd(); + static_cast(cpm)->stop_clock(clock); } uint32_t diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/cpm/src/jz4740.cc --- a/pkg/devices/lib/cpm/src/jz4740.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/cpm/src/jz4740.cc Sat Jan 16 23:47:39 2021 +0100 @@ -3,7 +3,7 @@ * provided by the jz4740 and related SoCs. The power management * functionality could be exposed using a separate driver. * - * Copyright (C) 2017, 2018 Paul Boddie + * Copyright (C) 2017, 2018, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -90,16 +90,33 @@ // Clock/timer control. +uint32_t +Cpm_jz4740_chip::get_clock_gate_value(enum Clock_identifiers clock) +{ + switch (clock) + { + case Clock_lcd: return (1 << Clock_gate_lcd); + case Clock_timer: return (1 << Clock_gate_timer); + default: return 0; + } +} + int -Cpm_jz4740_chip::have_clock() +Cpm_jz4740_chip::have_clock(enum Clock_identifiers clock) { - return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); + return !(_regs[Clock_gate] & get_clock_gate_value(clock)); } void -Cpm_jz4740_chip::start_clock() +Cpm_jz4740_chip::start_clock(enum Clock_identifiers clock) { - _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); + _regs[Clock_gate] = _regs[Clock_gate] & ~get_clock_gate_value(clock); +} + +void +Cpm_jz4740_chip::stop_clock(enum Clock_identifiers clock) +{ + _regs[Clock_gate] = _regs[Clock_gate] | get_clock_gate_value(clock); } // PLL control. @@ -261,22 +278,6 @@ -// LCD clock control. - -void -Cpm_jz4740_chip::start_lcd() -{ - _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_lcd); -} - -void -Cpm_jz4740_chip::stop_lcd() -{ - _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_lcd); -} - - - uint32_t Cpm_jz4740_chip::get_pll_frequency() { @@ -348,27 +349,21 @@ } int -jz4740_cpm_have_clock(void *cpm) +jz4740_cpm_have_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->have_clock(); + return static_cast(cpm)->have_clock(clock); } void -jz4740_cpm_start_clock(void *cpm) +jz4740_cpm_start_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_clock(); + static_cast(cpm)->start_clock(clock); } void -jz4740_cpm_start_lcd(void *cpm) +jz4740_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_lcd(); -} - -void -jz4740_cpm_stop_lcd(void *cpm) -{ - static_cast(cpm)->stop_lcd(); + static_cast(cpm)->stop_clock(clock); } uint32_t diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/cpm/src/jz4780.cc --- a/pkg/devices/lib/cpm/src/jz4780.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Sat Jan 16 23:47:39 2021 +0100 @@ -120,17 +120,8 @@ Clock_gate_smb4 = 12, // SMB4 (in CLKGR1) Clock_gate_smb3 = 0, // SMB3 (in CLKGR1) Clock_gate_smb2 = 25, // SMB2 (in CLKGR0) - Clock_gate_smb1 = 6, // SMB2 (in CLKGR0) - Clock_gate_smb0 = 5, // SMB2 (in CLKGR0) -}; - -enum Clock_gate_regs : unsigned -{ - Clock_gate_reg_smb4 = Clock_gate1, - Clock_gate_reg_smb3 = Clock_gate1, - Clock_gate_reg_smb2 = Clock_gate0, - Clock_gate_reg_smb1 = Clock_gate0, - Clock_gate_reg_smb0 = Clock_gate0, + Clock_gate_smb1 = 6, // SMB1 (in CLKGR0) + Clock_gate_smb0 = 5, // SMB0 (in CLKGR0) }; enum Divider_bits : unsigned @@ -172,19 +163,55 @@ } // Clock/timer control. -// NOTE: For the time being, assume that the system is configured. + +uint32_t +Cpm_jz4780_chip::get_clock_gate_register(enum Clock_identifiers clock) +{ + switch (clock) + { + case Clock_hdmi: return Clock_gate1; + case Clock_smb4: return Clock_gate1; + case Clock_smb3: return Clock_gate1; + default: return Clock_gate0; + } +} + +uint32_t +Cpm_jz4780_chip::get_clock_gate_value(enum Clock_identifiers clock) +{ + switch (clock) + { + case Clock_lcd: return (1 << Clock_gate_lcd1) | (1 << Clock_gate_lcd0); + case Clock_hdmi: return (1 << Clock_gate_hdmi); + case Clock_smb4: return (1 << Clock_gate_smb4); + case Clock_smb3: return (1 << Clock_gate_smb3); + case Clock_smb2: return (1 << Clock_gate_smb2); + case Clock_smb1: return (1 << Clock_gate_smb1); + case Clock_smb0: return (1 << Clock_gate_smb0); + default: return 0; + } +} int -Cpm_jz4780_chip::have_clock() +Cpm_jz4780_chip::have_clock(enum Clock_identifiers clock) { - // return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); - return 1; + return !(_regs[get_clock_gate_register(clock)] & get_clock_gate_value(clock)); } void -Cpm_jz4780_chip::start_clock() +Cpm_jz4780_chip::start_clock(enum Clock_identifiers clock) { - // _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); + uint32_t gate = get_clock_gate_register(clock); + + _regs[gate] = _regs[gate] & ~get_clock_gate_value(clock); +} + +void +Cpm_jz4780_chip::stop_clock(enum Clock_identifiers clock) +{ + uint32_t gate = get_clock_gate_register(clock); + + _regs[gate] = _regs[gate] | get_clock_gate_value(clock); } @@ -431,75 +458,6 @@ -// Clock gating control. - -void -Cpm_jz4780_chip::start_hdmi() -{ - _regs[Clock_gate1] = _regs[Clock_gate1] & ~(1 << Clock_gate_hdmi); -} - -void -Cpm_jz4780_chip::stop_hdmi() -{ - _regs[Clock_gate1] = _regs[Clock_gate1] | (1 << Clock_gate_hdmi); -} - -void -Cpm_jz4780_chip::start_lcd() -{ - // JZ4780 apparently needs LCD0/TVE to be ungated for the LCD peripheral to - // work. The Linux 3.0.8 vendor kernel reveals that the TVE clock is actually - // LCD0 and that the LCD clock is actually LCD1. - - // According to the 3.0.8 kernel, LCD1 is the parent of LCD0. However, LCD0 - // does seem to operate without LCD1 enabled. - - _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd1); - _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd0); -} - -void -Cpm_jz4780_chip::stop_lcd() -{ - _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd1); - _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd0); -} - -void -Cpm_jz4780_chip::_update_i2c(uint8_t channel, int enable) -{ - uint8_t bit; - uint32_t reg; - switch (channel) - { - case 0: bit = Clock_gate_smb0; reg = Clock_gate_reg_smb0; break; - case 1: bit = Clock_gate_smb1; reg = Clock_gate_reg_smb1; break; - case 2: bit = Clock_gate_smb2; reg = Clock_gate_reg_smb2; break; - case 3: bit = Clock_gate_smb3; reg = Clock_gate_reg_smb3; break; - case 4: bit = Clock_gate_smb4; reg = Clock_gate_reg_smb4; break; - default: return; - } - if (enable) - _regs[reg] = _regs[reg] & ~(1 << bit); - else - _regs[reg] = _regs[reg] | (1 << bit); -} - -void -Cpm_jz4780_chip::start_i2c(uint8_t channel) -{ - _update_i2c(channel, 1); -} - -void -Cpm_jz4780_chip::stop_i2c(uint8_t channel) -{ - _update_i2c(channel, 0); -} - - - // Clock sources. uint8_t @@ -858,41 +816,21 @@ } int -jz4780_cpm_have_clock(void *cpm) +jz4780_cpm_have_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->have_clock(); + return static_cast(cpm)->have_clock(clock); } void -jz4780_cpm_start_clock(void *cpm) +jz4780_cpm_start_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_clock(); -} - - - -void -jz4780_cpm_start_hdmi(void *cpm) -{ - static_cast(cpm)->start_hdmi(); + static_cast(cpm)->start_clock(clock); } void -jz4780_cpm_stop_hdmi(void *cpm) -{ - static_cast(cpm)->stop_hdmi(); -} - -void -jz4780_cpm_start_lcd(void *cpm) +jz4780_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_lcd(); -} - -void -jz4780_cpm_stop_lcd(void *cpm) -{ - static_cast(cpm)->stop_lcd(); + static_cast(cpm)->stop_clock(clock); } diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/dma/src/jz4730.cc --- a/pkg/devices/lib/dma/src/jz4730.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/dma/src/jz4730.cc Sat Jan 16 23:47:39 2021 +0100 @@ -406,7 +406,7 @@ { // Make sure that the DMA clock is available. - _cpm->start_dma(); + _cpm->start_clock(Clock_dma); // Enable the channel. // NOTE: No configuration is done for channel priority mode. diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/i2c/src/jz4730.cc --- a/pkg/devices/lib/i2c/src/jz4730.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/i2c/src/jz4730.cc Sat Jan 16 23:47:39 2021 +0100 @@ -89,7 +89,7 @@ { // Make sure that the I2C clock is available. - _cpm->start_i2c(); + _cpm->start_clock(Clock_i2c); // Set the bus clock frequency. diff -r c09f21715d8d -r 47295373521e pkg/devices/lib/i2c/src/jz4780.cc --- a/pkg/devices/lib/i2c/src/jz4780.cc Sat Jan 16 23:10:48 2021 +0100 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Sat Jan 16 23:47:39 2021 +0100 @@ -1,7 +1,7 @@ /* * I2C support for the JZ4780. * - * Copyright (C) 2017, 2018 Paul Boddie + * Copyright (C) 2017, 2018, 2021 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -628,10 +628,11 @@ I2c_jz4780_chip::get_channel(uint8_t channel) { l4_addr_t block = _start + channel * Smb_block_offset; + enum Clock_identifiers bits[] = {Clock_smb0, Clock_smb1, Clock_smb2, Clock_smb3, Clock_smb4}; - if (block < _end) + if (channel < 5) { - _cpm->start_i2c(channel); + _cpm->start_clock(bits[channel]); return new I2c_jz4780_channel(block, _cpm, _frequency); } else